Lifetime of object in lambda connected to pyqtSignal

The lambda in your example forms a closure. That is, it is a nested function that references objects available in its enclosing scope. Every function that creates a closure keeps a cell object for every item it needs to maintain a reference to.

In your example, the lambda creates a closure with references to the local self and model variables inside the scope of the __init__ method. If you keep a reference to the lambda somewhere, you can examine all the cell objects of its closure via its __closure__ attribute. In your example, it would display something like this:

>>> print(func.__closure__)
(<cell at 0x7f99c16c5138: MyModel object at 0x7f99bbbf0948>, <cell at 0x7f99c16c5168: MyClass object at 0x7f99bbb81390>)

If you deleted all other references to the MyModel and MyClass objects shown here, the ones kept by the cells would still remain. So when it comes to object cleanup, you should always explicitly disconnect all signals connected to functions that may form closures over the relevant objects.


Note that when it comes to signal/slot connections, PyQt treats wrapped C++ slots and Python instance methods differently. The reference counts of these types of callable are not increased when they are connected to signals, whereas lambdas, defined functions, partial objects and static methods are. This means that if all other references to the latter types of callable are deleted, any remaining signal connections will keep them alive. Disconnecting the signals will allow such connected callables to be garbage-collected, if necessary.

The one exception to the above is class methods. PyQt creates a special wrapper when creating connections to these, so if all other references to them are deleted, and the signal is emitted, an exception will be raised, like this:

TypeError: 'managedbuffer' object is not callable

The above should apply to PyQt5 and most versions of PyQt4 (4.3 and greater).

Leave a Comment