[PyQt] Garbage collection, signals to partial functions

Phil Thompson phil at riverbankcomputing.com
Tue Nov 17 16:38:29 GMT 2009


On Tue, 17 Nov 2009 17:31:29 +0100, Martin Teichmann
<martin.teichmann at mbi-berlin.de> wrote:
> Hi List,
> 
> already recently, I reported a problem with
> partial functions as slots not being correctly
> garbage collected. As Phil noted, this was
> fixed in recent snapshots. But since my
> code still wouldn't run properly, I investigated
> a bit more and wrote the following new test case,
> where still the objects are not garbage collected,
> although they should be.
> 
> This time I tested with latest snapshot
> (4.6.2-snapshot-20091115 and 4.9.2-snapshot-20091115)
> 
> Greetings
> 
> Martin
> 
> Here we go:
> 
> --------------------- snip --------------------------
> import gc
> from PyQt4 import QtCore
> from weakref import ref
> from functools import partial
> import sys
> 
> class A(QtCore.QObject):
>     def f(self, x):
>         print x
> 
> # make 2 objects of A
> b = A()
> a = A(b)
> # last line is the important difference to
> # previously reported problems. b is now parent of a.
> 
> # connect a signal to a partial function
> f = b.f
> p = partial(f, 3)
> a.connect(a, QtCore.SIGNAL("a"), p)
> wf = ref(f)
> wp = ref(p)
> f = None
> p = None
> 
> # kill all references
> wa = ref(a)
> wb = ref(b)
> a = None
> b = None
> 
> # but they're still here!
> # (following line prints four objects, but should print four Nones)
> print wa(), wb(), wp(), wf()
> 
> # OK, let's garbage collect
> gc.collect()
> 
> # still everything there (again, not a single None)
> print wa(), wb(), wp(), wf()
> 
> # that's the bug: still one reference, but no referrer
> # (the line prints 1 [], getrefcount always gives 1 to high)
> if wp() is not None:
>     print sys.getrefcount(wp()) - 1, gc.get_referrers(wp())
> 
> # assert that everything is gone
> assert wa() is None
> assert wb() is None
> assert wp() is None
> assert wf() is None

The proxies that wrap Python callables don't get deleted until the event
loop is run. I'd change your code to start a timer, enter the event loop,
and check the references when the timer times out.

Phil


More information about the PyQt mailing list