[PyQt] Python properties on virtual methods

Alessandro Pasotti apasotti at gmail.com
Wed Apr 22 21:50:26 BST 2015


2015-04-21 18:09 GMT+02:00 Phil Thompson <phil at riverbankcomputing.com>:

> On 21/04/2015 4:48 pm, Alessandro Pasotti wrote:
>
>> 2015-04-21 17:20 GMT+02:00 Phil Thompson <phil at riverbankcomputing.com>:
>>
>>  On 21/04/2015 4:12 pm, Alessandro Pasotti wrote:
>>>
>>>  Hi,
>>>>
>>>> I noticed that if I create a property() alias on a virtual method, the
>>>> alias will always call the base class method instead of the concrete
>>>> instance method.
>>>>
>>>> Is this the expected behaviour?
>>>> Is it documented somewhere?
>>>>
>>>> Here using PyQt4 4.8.5 and python 2.7, SIP should be 4.15.5
>>>>
>>>>
>>> A simple, complete example that demonstrates the problem would help.
>>>
>>>
>>
>> Hi Phil,
>>
>> I know an example would help but a simple one is not possible: I'm working
>> on a QT app embedded in a python plugin embedded in a 10K sloc C++ app.
>>
>> But, I try.
>>
>> instance "d" is a QgsPostgresProvider : public QgsVectorDataProvider
>>
>> https://github.com/elpaso/QGIS/blob/master/src/providers/postgres/qgspostgresprovider.h
>> which is a subclass of QgsVectorDataProvider
>>
>> https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.h
>> API Docs: http://qgis.org/api/qgsvectordataprovider_8h_source.html
>>
>>
>> In [70]: d = l.dataProvider()
>>
>>
>> In [71]: d
>>
>> Out[71]: <qgis._core.QgsVectorDataProvider at 0x7f132375fb00>
>>
>>
>> In [72]: d.capabilities?
>>
>> Docstring: QgsVectorDataProvider.capabilities() -> int
>>
>> Type: builtin_function_or_method
>>
>>
>> In [73]: d.capabilities()
>>
>> Out[73]: 115615
>>
>>
>> In [74]: d.__class__.capabilities2 = property(d.__class__.capabilities)
>>
>>
>> In [75]: d.capabilities2?
>>
>> Type: property
>>
>> String form: <property object at 0x7f1322ac6470>
>>
>> Docstring: QgsVectorDataProvider.capabilities() -> int
>>
>>
>>
>> In [76]: d.capabilities2
>>
>> Out[76]: 0
>>
>>
>> The problem is that instruction 73 calls
>> QgsPostgresProvider::capabilities() while instruction 76 calls
>> QgsVectorDataProvider::capabilities()
>>
>> https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.cpp#L107
>> and returns 0 (NO CAPABILITIES).
>>
>> Am I doing something wrong?
>>
>
> I have no idea. The firts person to ask is whoever did the Qgs bindings.
>
> Phil
>


I asked to the bindings author,

for the records, when the python object represents a pointer to a base
class, assigning a property on __class__ will always call the base class
method and not the instance's overridden method.

In my case,

l.p_dataProvider

Out[6]: <qgis._core.QgsVectorDataProvider at 0x7f22d15cac30>

but "l" is an instance of QgsPostgresProvider.


This is the answer from Martin Dobias who helped me to solve the problem:

I think your problem is not specific to PyQGIS. I tried this code:

class C(object):
  def f(self):
    return 0

class D(C):
  def f(self):
    return 42

C.g = property(C.f)

d = D()
print d.f()
print d.g

This is basically equivalent of your code, just with plain Python. It will
print 42 and 0. The reason is that the property is set to always call base
class method C.f() - you would need to use object instance to make python
do the call as one would (e.g. self.f()). With this modification you can
get both print statements return 42:

C.g = property( lambda self: self.f() )

In this way the method f() is resolved dynamically, because it is called
with instance, not class.


-- 
Alessandro Pasotti
w3:   www.itopen.it
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20150422/6a1160eb/attachment.html>


More information about the PyQt mailing list