3.3.1 弱参照オブジェクト

弱参照オブジェクトは属性あるいはメソッドを持ちません。しかし、リファレントがまだ存在するならば、呼び出すことでそのリファレントを取得できるようにします:

>>> import weakref
>>> class Object:
...     pass
...
>>> o = Object()
>>> r = weakref.ref(o)
>>> o2 = r()
>>> o is o2
True

リファレントがもはや存在しないならば、参照オブジェクトの呼び出しはNoneを返します:

>>> del o, o2
>>> print r()
None

弱参照オブジェクトがまだ生きているかどうかのテストは、式ref() is not Noneを用いて行われます。通常、参照オブジェクトを使う必要があるアプリケーションコードはこのパターンに従います:

# rは弱参照オブジェクト
o = r()
if o is None:
    # リファレントがガーベジコレクトされた
    print "Object has been allocated; can't frobnicate."
else:
    print "Object is still live!"
    o.do_something_useful()

``生存性(liveness)''のテストを個々に行うと、スレッド化されたアプリケーションにおいて競合状態を作り出します。弱参照が呼び出される前に、他のスレッドは弱参照が無効になる原因となり得ます。上で示したイディオムは、シングルスレッド化されたアプリケーションと同じくスレッド化されたアプリケーションにおいて安全です。

サブクラス化を行えば、ref オブジェクトの特殊なバージョンを 作成できます。これはWeakValueDictionary の実装で使われており、 マップ内の各エントリによるメモリのオーバヘッドを減らしています。 こうした実装は、ある参照に追加情報を関連付けたい場合に便利ですし、 リファレントを取り出すための呼び出し時に何らかの追加処理を行いたい 場合にも使えます。

以下の例では、ref のサブクラスを使って、あるオブジェクトに 追加情報を保存し、リファレントがアクセスされたときにその値に作用 をできるようにするための方法を示しています:

import weakref

class ExtendedRef(weakref.ref):
    def __new__(cls, ob, callback=None, **annotations):
        weakref.ref.__new__(cls, ob, callback)
        self.__counter = 0

    def __init__(self, ob, callback=None, **annotations):
        super(ExtendedRef, self).__init__(ob, callback)
        for k, v in annotations:
            setattr(self, k, v)

    def __call__(self):
        """Return a pair containing the referent and the number of
        times the reference has been called.
        """
        ob = super(ExtendedRef, self)()
        if ob is not None:
            self.__counter += 1
            ob = (ob, self.__counter)
        return ob

ご意見やご指摘をお寄せになりたい方は、 このドキュメントについて... をご覧ください。