24

Djangoのドキュメントでは、この件について次のように述べています。

また、Djangoはデフォルトでシグナルハンドラーを弱参照として保存するため、ハンドラーがローカル関数の場合、ガベージコレクションされる可能性があることにも注意してください。これを防ぐには、シグナルのconnect()を呼び出すときにweak=Falseを渡します。

これがデフォルトである理由の正当性を見つけることができませんでした。また、明示的に登録したシグナルを暗黙的に非表示にする必要がある理由がわかりません。では、ここでの弱参照のユースケースは何ですか?そして、なぜそれがデフォルトなのですか?

どちらの場合も99%は問題ないのではないかと思いますが、ここでわからないことがあるので、いつか噛み付くような「落とし穴」が潜んでいないか知りたいです。

4

2 に答える 2

14

シグナルハンドラーは、シグナルがまだ飛び回っているという理由だけで、参照するオブジェクトがガベージコレクションされないように(たとえば、シグナルハンドラーを明示的に削除した後)、弱参照として格納されます。

于 2009-07-10T17:26:14.897 に答える
6

バインドされたメソッドは、それらが属するオブジェクトへの参照を保持します(そうでない場合、Pythonのドキュメントselfを参照して埋めることはできません)。次のコードを検討してください。

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>]
[]

コールバックでweakrefsを保持するときに知っておくべき重要なことの1つは、weakrefバインドされたメソッドは常にオンザフライで作成されるため、直接weakrefバインドすることはできないということです。

>>> 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>
于 2009-07-10T18:46:07.793 に答える