[PyQt] SIP: Retaining python class variables of derived C++ class

Matthias Kuhn matthias at opengis.ch
Wed Feb 6 11:41:09 GMT 2019


Hi

> On 7 Jan 2019, at 4:32 pm, Sandro Mani <[hidden email]
> <http://python.6.x6.nabble.com/user/SendEmail.jtp?type=node&node=5246016&i=0>>
> wrote:
>
> > 
> > Hi
> > 
> > I have the following scenario:
> > 
> > -----------
> > 
> > 
> > C++:
> > 
> > class AbstractItem {
> >     AbstractItem(const QString& id);
> >     virtual ~AbstractItem();
> > };
> > 
> > 
> > class Pool {
> >     void addItem(AbstractItem* item /Transfer/);
> >     AbstractItem* getItem(const QString& id);
> > };
> > 
> > 
> > 
> > 
> > Python:
> > 
> > class Item(AbstractItem):
> >     def __init__(self, id):
> >         AbstractItem.__init__(self, id)
> >         self.value = "value"
> >     def getValue(self):
> >         return self.value
> > 
> > 
> > pool = Pool()
> > pool.addItem(Item("xyz"))
> > # ...
> > item = pool.getItem("xyz")
> > print(item.getValue()) ### AttributeError: 'Item' object has no attribute 'value'
> > 
> > 
> > -----------
> > 
> > 
> > The issue is that, when I pass the Python-deriver Item instance to the pool, lose the reference to it, and then
> re-retreive it from the pool, the Item instance will have lost class
> variables set in the Item __init__ function. As I understand, this is
> expected, because SIP keeps a python part and a c++ part of each
> object, and the python part is garbage-collected when the variable
> gets out of scope. Is there a way to make the above logic work?
> ... [show rest of quote]
>
> Use of /Transfer/ should get the behaviour that you want. However you
> need to make sure you are using the right supertype for any classes
> that implement any sort of ownership rules. Adding the
> /Supertype=sip.wrapper/ class annotation to both AbstractItem and Pool
> classes may help.
>
> Phil 

PSA:

After the latest insights into how /Transfer/ works, I was able to find
a solution for this.

As soon as the Transfer annotation is involved, the target class wrapper
(the pool in this case) will hold a reference to the transferred child
wrapper (item subclass here). If pool's wrapper gets garbage collected,
the transferred item's wrapper is free to be garbage collected as well.

To avoid this issue, there are the following possibilities I can see

  * Keep a reference to the item subclass (the current workaround)
  * Keep a (global or long-living) reference to the pool
  * And for singleton-like classes: add a /KeepReference/ annotation to
    the getter of the pool (see https://github.com/qgis/QGIS/pull/9112)

Regards

Matthias

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190206/8417f0d6/attachment.html>


More information about the PyQt mailing list