Why does Django's signal handling use weak references for callbacks by default? Why does Django's signal handling use weak references for callbacks by default? python python

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


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.


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 gcclass SomeLargeObject(object):    def on_foo(self): passslo = SomeLargeObject()callbacks = [slo.on_foo]print [o for o in gc.get_objects() if isinstance(o, SomeLargeObject)]del sloprint [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>