Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

The Django docs say this on the subject:

Note also that Django stores signal handlers as weak references by default, so if your handler is a local function, it may be garbage collected. To prevent this, pass weak=False when you call the signal’s connect().

I haven't been able to find any justification for why this is the default, and I don't understand why you would ever want a signal that you explicitly registered to implicitly disappear. So what is the use-case for weak references here? And why is it the default?

I realize it probably doesn't matter either way in 99% of cases, but clearly there's something I don't understand here, and I want to know if there's any "gotchas" lurking that might bite me someday.

like image 687
Jason Creighton Avatar asked Jul 10 '09 16:07

Jason Creighton


People also ask

What is the use of the Post_delete signal in Django?

Django Signals - post_delete()To notify another part of the application after the delete event of an object happens, you can use the post_delete signal.

How does signal work in Django?

Django includes a “signal dispatcher” which helps decoupled applications get notified when actions occur elsewhere in the framework. In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place.

Are Django signals asynchronous?

To answer directly: No. It's sync.

What are Django signals explain its types?

There are 3 types of signal. pre_save/post_save: This signal works before/after the method save(). pre_delete/post_delete: This signal works before after delete a model's instance (method delete()) this signal is thrown. pre_init/post_init: This signal is thrown before/after instantiating a model (__init__() method).


2 Answers

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.

like image 143
Luper Rouch Avatar answered Oct 01 '22 19:10

Luper Rouch


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> 
like image 20
Torsten Marek Avatar answered Oct 01 '22 19:10

Torsten Marek