Почему в обработке сигналов Django по умолчанию используются слабые ссылки для обратных вызовов? - PullRequest
18 голосов
/ 10 июля 2009

Документы Django говорят это по теме:

Обратите внимание, что Django хранит сигнал обработчики как слабые ссылки по умолчанию, так что если ваш обработчик является локальным функция, это может быть сборщик мусора. Чтобы предотвратить это, передайте слабый = Ложный, когда Вы вызываете сигнал подключения ().

Я не смог найти никакого оправдания тому, почему это значение по умолчанию, и я не понимаю, почему вы хотели бы, чтобы сигнал, который вы явно зарегистрировали, неявно исчезал. Так каков вариант использования слабых ссылок здесь? И почему это по умолчанию?

Я понимаю, что, вероятно, это не имеет значения в любом случае в 99% случаев, но ясно, что есть кое-что, чего я здесь не понимаю, и я хочу знать, есть ли какие-то "ловушки", которые могут когда-нибудь меня укусить. *

Ответы [ 2 ]

11 голосов
/ 10 июля 2009

Обработчики сигналов хранятся в виде слабых ссылок, чтобы объект, на который они ссылаются, не собирался мусором (например, после явного удаления обработчика сигналов) только потому, что сигнал все еще летает.

6 голосов
/ 10 июля 2009

Связанные методы сохраняют ссылку на объект, которому они принадлежат (в противном случае они не могут заполнить 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)]

Выход:

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

При хранении слабых ссылок на обратные вызовы важно знать, что вы не можете напрямую связывать методы со слабыми ссылками, поскольку они всегда создаются на лету:

>>> 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>
...