[PyQt] signals to python-alive, Qt-dead objects

Martin Teichmann martin.teichmann at mbi-berlin.de
Fri Apr 23 09:59:02 BST 2010


Hi List,

taking the risk of annoying people by asking again,
(I didn't get a response last time)
I would like to kindly ask if the following behavior is
really intended for PyQt4:

If a QObject is not used anymore, it gets deleted by
Qt, and eventually garbage collected some time later.
In the meantime, however, PyQt4 still delivers signals
to the object, leading to a RuntimeError, since the
C++ object is already deleted. C++ has the standard
behaviour that upon deletion of an object, all signals
automatically get disconnected. This is very useful,
since I (as a programmer) don't need to care about this
anymore.

So, if this intended behaviour, how do I go about it?
Sure, I could write a try:...except RuntimeError: around
every method that I use as a slot, but that's some pain.

If that was directly implemented in PyQt4, it would be
much simpler: a simple if statement that checks
if a QObject is still C++-alive before delivering signals would
do the job. I also cannot see any drawbacks: since the
receiving object cannot do much anymore anyway,
given that its object has been deleted, I cannot imagine
that anyone depends on the current behaviour.

I re-send the code that shows the problem, I just tested
it with PyQt 4.7.3 under Python 2.6 and Windows XP.
Note that the garbage collection at the very end does
make a difference, which it should never do, since
it happens at random intervals and is thus not
reliable (all of which is intended behaviour).

Greetings

Martin

------------------------ snip ----------------------------
from PyQt4.QtCore import QObject, SIGNAL, QCoreApplication
import gc

# following two lines not important
from sys import argv
app = QCoreApplication(argv)

class A(QObject):
   def __init__(self, p=None):
       QObject.__init__(self, p)

   def g(self):
       self.emit(SIGNAL("sig"))

   def k(self):
       self.emit(SIGNAL("kill"))

   def f(self):
       try:
           print self.children() # only to test if C++ object is still alive
       except RuntimeError:
           print "hey, caught runtime error!"

   def kill(self):
       self.setParent(None)

a = A()
b = A(a)
c = A(b)

b.connect(a, SIGNAL("sig"), c.f)
b.connect(a, SIGNAL("kill"), b.kill)

a.g() # deliver signal to c, all fine
c.v = c # create cycle to prevent immediate collection
b = None
c = None
a.k() # now c ceases existence in the C++ world
print "here"
a.g() # signal is still delivered
print "now collect"
gc.collect()
a.g() # signal no more delivered, python object has died
---------------------------------------- snip -----------------------------


More information about the PyQt mailing list