[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    Re: [PyQt] Python properties on virtual methods
From:       Alessandro Pasotti <apasotti () gmail ! com>
Date:       2015-04-22 20:50:26
Message-ID: CAL5Q672-tJx-s10K2YqJagpHb6kmQOvOaj4tNR2LmeJeyNxCzQ () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


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

> On 21/04/2015 4:48 pm, Alessandro Pasotti wrote:
>
>> 2015-04-21 17:20 GMT+02:00 Phil Thompson <phil@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

[Attachment #5 (text/html)]

<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">2015-04-21 18:09 \
GMT+02:00 Phil Thompson <span dir="ltr">&lt;<a \
href="mailto:phil@riverbankcomputing.com" \
target="_blank">phil@riverbankcomputing.com</a>&gt;</span>:<br><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"><div><div>On 21/04/2015 4:48 pm, Alessandro \
Pasotti wrote:<br> <blockquote class="gmail_quote" style="margin:0px 0px 0px \
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> 2015-04-21 17:20 \
GMT+02:00 Phil Thompson &lt;<a href="mailto:phil@riverbankcomputing.com" \
target="_blank">phil@riverbankcomputing.com</a>&gt;:<br> <br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"> On 21/04/2015 4:12 pm, Alessandro Pasotti \
wrote:<br> <br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex"> Hi,<br>
<br>
I noticed that if I create a property() alias on a virtual method, the<br>
alias will always call the base class method instead of the concrete<br>
instance method.<br>
<br>
Is this the expected behaviour?<br>
Is it documented somewhere?<br>
<br>
Here using PyQt4 4.8.5 and python 2.7, SIP should be 4.15.5<br>
<br>
</blockquote>
<br>
A simple, complete example that demonstrates the problem would help.<br>
<br>
</blockquote>
<br>
<br>
Hi Phil,<br>
<br>
I know an example would help but a simple one is not possible: I&#39;m working<br>
on a QT app embedded in a python plugin embedded in a 10K sloc C++ app.<br>
<br>
But, I try.<br>
<br>
instance &quot;d&quot; is a QgsPostgresProvider : public QgsVectorDataProvider<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/providers/postgres/qgspostgresprovider.h" \
target="_blank">https://github.com/elpaso/QGIS/blob/master/src/providers/postgres/qgspostgresprovider.h</a><br>
 which is a subclass of QgsVectorDataProvider<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.h" \
target="_blank">https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.h</a><br>
 API Docs: <a href="http://qgis.org/api/qgsvectordataprovider_8h_source.html" \
target="_blank">http://qgis.org/api/qgsvectordataprovider_8h_source.html</a><br> <br>
<br>
In [70]: d = l.dataProvider()<br>
<br>
<br>
In [71]: d<br>
<br>
Out[71]: &lt;qgis._core.QgsVectorDataProvider at 0x7f132375fb00&gt;<br>
<br>
<br>
In [72]: d.capabilities?<br>
<br>
Docstring: QgsVectorDataProvider.capabilities() -&gt; int<br>
<br>
Type: builtin_function_or_method<br>
<br>
<br>
In [73]: d.capabilities()<br>
<br>
Out[73]: 115615<br>
<br>
<br>
In [74]: d.__class__.capabilities2 = property(d.__class__.capabilities)<br>
<br>
<br>
In [75]: d.capabilities2?<br>
<br>
Type: property<br>
<br>
String form: &lt;property object at 0x7f1322ac6470&gt;<br>
<br>
Docstring: QgsVectorDataProvider.capabilities() -&gt; int<br>
<br>
<br>
<br>
In [76]: d.capabilities2<br>
<br>
Out[76]: 0<br>
<br>
<br>
The problem is that instruction 73 calls<br>
QgsPostgresProvider::capabilities() while instruction 76 calls<br>
QgsVectorDataProvider::capabilities()<br>
<a href="https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.cpp#L107" \
target="_blank">https://github.com/elpaso/QGIS/blob/master/src/core/qgsvectordataprovider.cpp#L107</a><br>
 and returns 0 (NO CAPABILITIES).<br>
<br>
Am I doing something wrong?<br>
</blockquote>
<br></div></div>
I have no idea. The firts person to ask is whoever did the Qgs bindings.<span><font \
color="#888888"><br> <br>
Phil<br></font></span></blockquote><div><br><br></div><div>I asked to the bindings \
author,<br><br></div><div>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&#39;s overridden method.<br><br></div><div>In my \
case, <br><br>

<p style="margin:0px;text-indent:0px">l.p_dataProvider</p>
<p style="margin:0px;text-indent:0px"><span \
style="color:rgb(139,0,0)">Out[</span><span \
style="font-weight:600;color:rgb(139,0,0)">6</span><span \
style="color:rgb(139,0,0)">]:</span> &lt;qgis._core.QgsVectorDataProvider at \
0x7f22d15cac30&gt;</p><p style="margin:0px;text-indent:0px"></p><p \
style="margin:0px;text-indent:0px">but &quot;l&quot; is an instance of \
QgsPostgresProvider.<br></p><br></div><div><br></div><div>This is the answer from \
Martin Dobias who helped me to solve the problem:<br></div><div><br><div>I think your \
problem is not specific to PyQGIS. I tried this \
code:</div><div><br></div><div><div>class C(object):</div><div>   def \
f(self):</div><div>      return 0</div><div><br></div><div>class D(C):</div><div>   \
def f(self):</div><div>      return 42</div><div><br></div><div>C.g = \
property(C.f)</div><div><br></div><div>d = D()</div><div>print d.f()</div><div>print \
d.g</div></div><div><br></div><div>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:</div><div><br></div><div>C.g = property( \
lambda self: self.f() )<br></div><div><br></div><div>In this way the method f() is \
resolved dynamically, because it is called with instance, not \
class.</div><br></div></div><br>-- <br><div>Alessandro Pasotti<br>w3:     <a \
href="http://www.itopen.it" target="_blank">www.itopen.it</a></div> </div></div>


[Attachment #6 (text/plain)]

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic