[PyQt] Inconsistent gc behavior for reference cycles introduced by connections to lambda

Ales Erjavec ales.erjavec324 at gmail.com
Mon Mar 26 12:57:24 BST 2018


Hi,

There appears to be inconsistency in traversing and GC-ing of some QObject
derived classes.

For instance connecting `QObject.objectNameChanged` signal to a lambda
(capturing
the the QObject instance), lists that lambda in the `gc.get_referents`
(assuming as
implemented by %GCTraverseCode in qobject.sip). Deleting a reference
for the object
and invoking `gc.collect` successfully disposes of the ref cycle.

However for QAbstractItemModel subclasses (QStringListModel,
QStandardListModel, ...)
this is not the case. They do no list the lambda slots in
`gc.get_referents` and leak the
reference cycle.

Example code:
```
import gc

from PyQt5.QtCore import QObject
from PyQt5.QtGui import QStandardItemModel, QTextDocument

obj = QObject()
obj.objectNameChanged.connect(lambda name, obj=obj: obj)
print(gc.get_referents(obj))  # has the lambda in forward reference traversal

del obj

gc.collect()

assert not [obj for obj in gc.get_objects() if isinstance(obj, QObject)]

doc = QTextDocument()
doc.objectNameChanged.connect(lambda name, obj=doc: None)

print(gc.get_referents(doc))  # has the lambda in forward reference traversal

del doc

gc.collect()

assert not [obj for obj in gc.get_objects() if isinstance(obj, QObject)]

model = QStandardItemModel()
model.objectNameChanged.connect(lambda name, obj=model: None)

print(gc.get_referents(model))  # no lambda in forward reference traversal

del model

gc.collect()

assert not [obj for obj in gc.get_objects() if isinstance(obj, QObject)]
```
The last assert fails because QStandardItemModel survived the collection.

Similarly plain QWidget's (and its python derived subclasses) traverse
connected slots,
but its builtin subclasses (QComboBox, QLabel, ...) do not.

There is nothing in the .sip definition files that would stand out as overriding
the default QObject's %GCTraverseCode so I am assuming this is not intended.

Tested on:
* Python: 3.5.4
* PyQt5: 5.9.2, 5.10.1
* OS: macOS 10.11

Regards
Aleš


More information about the PyQt mailing list