为什么Django的信号处理默认使用弱引用进行回调?

Jas*_*ton 18 python django garbage-collection weak-references django-signals

Django文档说这个关于这个问题:

另请注意,Django默认将信号处理程序存储为弱引用,因此如果您的处理程序是本地函数,则可能是垃圾回收.要防止这种情况,请在调用信号的connect()时传递weak = False.

我无法找到为什么这是默认值的任何理由,我不明白为什么你会希望你明确注册的信号隐式消失.那么弱引用的用例是什么?为什么它是默认值?

我意识到在99%的情况下这两种方式都没关系,但显然我在这里有一些不明白的东西,我想知道是否有任何"陷阱"潜伏在某一天可能会让我感到困惑.

Lup*_*uch 12

信号处理程序存储为弱引用,以避免它们引用的对象不被垃圾收集(例如在显式删除信号处理程序之后),仅仅因为信号仍在飞来飞去.

  • 您的信号处理程序可以是例如对象的方法.如果对象超出范围(或者你把它等等),你通常会认为它会收集垃圾,但是如果连接了一个非弱的信号,它就不会. (6认同)
  • 你是对的,所以要让信号处理程序被垃圾收集,没有弱引用,你必须做两件事:删除信号处理程序,并断开信号连接。这对每个人来说可能并不明显,所以我认为这就是默认使用弱引用的原因。 (2认同)
  • 抱歉,我这么密集,但我还是不明白。我想我理解您“断开”信号的含义:在“信号”实例上调用“断开”方法,并将处理程序作为参数传入。但是,“删除”信号处理程序是什么意思? (2认同)
  • 最后,我认为我的困惑根源在于与大多数人不同的期望……我认为在所有情况下必须显式注销信号是最有意义的,但是显然存在一些用例。弱引用行为。 (2认同)

Tor*_*rek 6

绑定方法保留对它们所属对象的引用(否则,它们无法填充self,参见Python文档).请考虑以下代码:

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)]
Run Code Online (Sandbox Code Playgroud)

输出:

[<__main__.SomeLargeObject object at 0x15001d0>]
[<__main__.SomeLargeObject object at 0x15001d0>]
[]
Run Code Online (Sandbox Code Playgroud)

在回调中保留weakrefs时要知道的一件重要事情是你不能直接弱化绑定方法,因为它们总是在动态创建:

>>> 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>
Run Code Online (Sandbox Code Playgroud)