[Django]-Why does Django's signal handling use weak references for callbacks by default?

14👍

Signals handlers are stored as weak references to avoid the object they reference from not being garbage collected (for example after explicit deletion of the signal handler), just because a signal is still flying around.

6👍

Bound methods keep a reference to the object they belong to (otherwise, they cannot fill self, cf. the Python documentation). Consider the following code:

import gc
class SomeLargeObject(object):
    def on_foo(self): pass

slo = SomeLargeObject()
callbacks = [slo.on_foo]

print [o for o in gc.get_objects() if isinstance(o, SomeLargeObject)]
del slo
print [o for o in gc.get_objects() if isinstance(o, SomeLargeObject)]
callbacks = []
print [o for o in gc.get_objects() if isinstance(o, SomeLargeObject)]

The output:

[<__main__.SomeLargeObject object at 0x15001d0>]
[<__main__.SomeLargeObject object at 0x15001d0>]
[]

One important thing to know when keeping weakrefs on callbacks is that you cannot weakref bound methods directly, because they are always created on the fly:

>>> class SomeLargeObject(object):
...  def on_foo(self): pass
>>> import weakref
>>> def report(o):
...  print "about to collect"
>>> slo = SomeLargeObject()
>>> #second argument: function that is called when weakref'ed object is finalized
>>> weakref.proxy(slo.on_foo, report)
about to collect
<weakproxy at 0x7f9abd3be208 to NoneType at 0x72ecc0>

Leave a comment