質問
誰でもできるのでは説明用の弱参照?
の 文書 かで正確には、それだけでは、GCを破壊できるオブジェクトにリンクを介して弱参照。そうした点にできるオブジェクトが消えですか?する必要が生じた場合はどうなるのに使用してそのままでは消失して?
ありがとうございます。説明していくつかの良い例は?
感謝
解決
は弱参照の典型的な用途は、AがBへの参照を持っており、Bが適切なサイクル検出ガベージコレクタなしA.への参照を持っている場合何の言及には存在しない場合でも、これらの2つのオブジェクトがGC'dを得ることはないですいずれかの「外」から。参考文献の一つが「弱い」である場合は、オブジェクトが正しくGC'dれます。
それはカウントされませんので、しかし、Pythonはのの、(2.0以降!)サイクル検出ガベージコレクタを持っています。)
弱参照の別の用途は、キャッシュにあります。これは、weakref
のマニュアルに記載されます:
GCは、これらのオブジェクトの1つを破壊することを決定し、そしてあなたがそれを必要とする場合は、弱参照のための主な用途は、キャッシュまたはマッピングに表示されますので、大きなオブジェクトを単独で生き続けられないこと。
希望の大型のオブジェクトを保持するキャッシュやマッピングを、実装することです
、あなただけのデータを再フェッチ/再計算することができます。
他のヒント
イベントは弱参照のための一般的なシナリオです。
<時間>問題
投・受光器:オブジェクトのペアを考えてみましょう。受信機は、エミッタより短い寿命を持っています。
あなたはこのような実装を試みることができます
class Emitter(object):
def __init__(self):
self.listeners = set()
def emit(self):
for listener in self.listeners:
# Notify
listener('hello')
class Receiver(object):
def __init__(self, emitter):
emitter.listeners.add(self.callback)
def callback(self, msg):
print 'Message received:', msg
e = Emitter()
l = Receiver(e)
e.emit() # Message received: hello
ただし、この場合、エミッタはレシーバへの参照を保持し、結合した方法callback
への参照を保持します。だから、投光器がReceiverが生き続けます:
# ...continued...
del l
e.emit() # Message received: hello
これは時々面倒です。そのEmitter
は、データの変更やReceiver
は、いくつかのUIコントロールを更新するために変更することに耳を傾け、ダイアログウィンドウによって作成された時を示すいくつかのデータモデルの一部である想像します。
、アプリケーションの生涯を通じ、複数のダイアログを生成でき、我々は彼らの受信機がまだウィンドウが閉じられた後も長い間、エミッタの内側に登録する必要はありません。つまり、メモリリークになります。
手動コールバックを削除する一つの選択肢(同様に厄介)であり、弱参照を使用して別のである。
<時間>ソリューション
通常のセットのように見えませんが、弱い参照を使用して、そのメンバーを格納し、もはや彼らが解放されたときにそれらを保存する素敵なクラスWeakSet
があります。
エクセレント!のは、それを使用してみましょう。
def __init__(self):
self.listeners = weakref.WeakSet()
と再び実行します:
e = Emitter()
l = Receiver(e)
e.emit()
del l
e.emit()
ああ、何もまったく起こりません!バインドされた方法は、(特定の受信者のcallback
)今孤立しているからだ - エミッタもレシーバでもないが、強い参照を保持します。したがって、それはごみすぐに集めています。
のは、レシーバー(ない投光器にこの時間を)作ってみましょう。このコールバックへの強い参照を保持します:
class Receiver(object):
def __init__(self, emitter):
# Create the bound method object
cb = self.callback
# Register it
emitter.listeners.add(cb)
# But also create an own strong reference to keep it alive
self._callbacks = set([cb])
今、私たちは、期待される動作を観察することができます:エミッターは限りレシーバが住んでいると、コールバックを保持します。
。e = Emitter()
l = Receiver(e)
assert len(e.listeners) == 1
del l
import gc; gc.collect()
assert len(e.listeners) == 0
<時間>
ボンネットの下に私は、受信機が本当にすぐにクリーンアップされていることを確認するには、ここgc.collect()
を入れて持っていたことに注意してください。今強い参照のサイクルがありますので、それをここで必要なの:バインドされた方法は、受信機およびその逆を意味します。
これは非常に悪いわけではありません。これは、受信機のクリーンアップは次のガベージコレクタの実行まで延期されることを意味します。循環参照は、単純な参照カウントメカニズムによってクリーンアップすることはできません。
あなたが本当にしたい場合は、、あなたはあまりにも弱い参照としてそのself
を続けるだろうカスタム関数オブジェクトにバインドされたメソッドを置き換えることで、強力な基準周期を取り除くことができます。
def __init__(self, emitter):
# Create the bound method object
weakself = weakref.ref(self)
def cb(msg):
self = weakself()
self.callback(msg)
# Register it
emitter.listeners.add(cb)
# But also create an own strong reference to keep it alive
self._callbacks = set([cb])
のヘルパー関数にそのロジックを入れてみましょう。
def weak_bind(instancemethod):
weakref_self = weakref.ref(instancemethod.im_self)
func = instancemethod.im_func
def callback(*args, **kwargs):
self = weakref_self()
bound = func.__get__(self)
return bound(*args, **kwargs)
return callback
class Receiver(object):
def __init__(self, emitter):
cb = weak_bind(self.callback)
# Register it
emitter.listeners.add(cb)
# But also create an own strong reference to keep it alive
self._callbacks = set([cb])
フルGCサイクルを必要とせずに、すぐに今、強い参照のないサイクルがありませんので、Receiver
が解放されると、コールバック関数はまた、解放された(とエミッタのWeakSet
から削除)されます。
- 弱参照は非常に重要なコンセプトは、pythonにおける欠 言語が好きでJava(java1.5)です。
にオブザーバーのデザインパターン、一般的に観察可能なオブジェクトを維持しなければならな 弱参照のオブザーバオブジェクトです。
例えば.る光のイベントのそれぞれについて、"これまで)およびBレジスタとそのた 聴イベントのそれぞれについて、"これまで).このように、それぞれについて、"これまで)が放出され、Bは 通知されます。ものの場合はBが不要となるためにアプリケーションに必要な なhinderanceの生ごみコレクション(年の 参照B)このように、場合には、保弱参照をBとが すべての参考にしてくださいそしてこないますのでゴミを収集します。
- でも非常に有用な実施のキャッシュの