Search code examples
pythongarbage-collectionpyqtpyqt4signals-slots

Does PyQT4 signal.connect keep objects live?


If I have a signal and I register an objects function to the signal will this keep the object live and stop the garbage collection of that object?

E.g.

class Signals():
    signal = Qt.pyqtSignal()
    def __init__(self):
        QObject.__init__(self)

class Test();
    def __init__(self, s):
        s.connect(self.done)

    def done(self):
        print("Done")

s = Signals()
t = Test(s.signal)
t = None
s.signal.emit()

Will the Test objecct still get the signal?


Solution

  • No, it won't, it's not enough to keep the object alive. Just try it:

    from PyQt4.QtCore import *
    
    app = QCoreApplication([])
    
    class Signals(QObject):
        signal = pyqtSignal()
        def __init__(self):
            QObject.__init__(self)
    
    class Test():
        def __init__(self, s):
            s.connect(self.done)
    
        def done(self):
            print("Done")
    
    
    s = Signals()
    t = Test(s.signal)
    print("first")
    s.signal.emit()
    app.processEvents()
    
    t = None
    print("second")
    s.signal.emit()
    app.processEvents()
    

    Output:

    first
    Done
    second
    

    This behaviour only applies when connecting a signal to a bound method. As an example, if you use:

    s.connect(lambda: self.done())
    

    instead, then it will work. If the library wouldn't keep a strong reference here, then you could never connect an anonymous function to a signal. So in this case pyqt has to ensure that it keeps a reference to the function, and the object (self) keeps to be referenced in the closure of the lambda.