8.11。 weakref —弱い参照
バージョン2.1の新機能。
ソースコード: :source: `Lib / weakref.py`
weakref モジュールを使用すると、Pythonプログラマーはオブジェクトへの弱参照を作成できます。
以下では、指示対象という用語は、弱参照によって参照されるオブジェクトを意味します。
オブジェクトへの弱い参照は、オブジェクトを存続させるのに十分ではありません。参照先への残りの参照が弱い参照だけである場合、ガベージコレクションは自由に参照先を破棄し、そのメモリを他の目的に再利用します。 弱参照の主な用途は、大きなオブジェクトを保持するキャッシュまたはマッピングを実装することです。大きなオブジェクトは、キャッシュまたはマッピングに表示されるという理由だけで存続させないことが望まれます。
たとえば、大きなバイナリイメージオブジェクトが多数ある場合は、それぞれに名前を関連付けることができます。 Pythonディクショナリを使用して名前を画像に、または画像を名前にマップした場合、画像オブジェクトは、ディクショナリに値またはキーとして表示されたという理由だけで存続します。 weakref モジュールによって提供される WeakKeyDictionary クラスと WeakValueDictionary クラスは代替手段であり、弱い参照を使用して、オブジェクトがマッピングオブジェクト。 たとえば、画像オブジェクトが WeakValueDictionary の値である場合、その画像オブジェクトへの最後の残りの参照が弱いマッピングによって保持されている弱い参照である場合、ガベージコレクションはオブジェクトとそれに対応するものを再利用できます。弱いマッピングのエントリは単に削除されます。
WeakKeyDictionary および WeakValueDictionary は、実装で弱参照を使用し、ガベージコレクションによってキーまたは値が再利用されたときに弱辞書に通知する弱参照にコールバック関数を設定します。 ほとんどのプログラムは、これらの弱辞書タイプの1つを使用するだけで十分であることに気付くはずです。通常、独自の弱参照を直接作成する必要はありません。 弱い辞書の実装で使用される低レベルの機構は、高度な使用のために weakref モジュールによって公開されます。
すべてのオブジェクトを弱く参照できるわけではありません。 クラスインスタンス、Pythonで記述された関数(Cでは記述されていない)、メソッド(バインドされたものとバインドされていないものの両方)、セット、フリーズセット、ファイルオブジェクト、ジェネレーター、タイプオブジェクト、 [を含むことができるオブジェクト bsddb モジュールのX240X]オブジェクト、ソケット、配列、両端キュー、正規表現パターンオブジェクト、およびコードオブジェクト。
バージョン2.4で変更:ファイル、ソケット、配列、およびパターンのサポートが追加されました。
バージョン2.7で変更: thread.lock、threading.Lock、およびコードオブジェクトのサポートが追加されました。
list
や dict などのいくつかの組み込み型は、弱参照を直接サポートしていませんが、サブクラス化を通じてサポートを追加できます。
class Dict(dict):
pass
obj = Dict(red=1, green=2, blue=3) # this object is weak referenceable
弱参照をサポートするために拡張タイプを簡単に作成できます。 弱参照サポートを参照してください。
- class weakref.ref(object[, callback])
オブジェクトへの弱参照を返します。 指示対象がまだ生きている場合は、参照オブジェクトを呼び出すことで元のオブジェクトを取得できます。 指示対象がもう生きていない場合、参照オブジェクトを呼び出すと、 None が返されます。 callback が提供され、 None が提供されておらず、返されたweakrefオブジェクトがまだ存続している場合、オブジェクトがファイナライズされようとしているときにコールバックが呼び出されます。 弱参照オブジェクトは、コールバックへの唯一のパラメーターとして渡されます。 指示対象は利用できなくなります。
同じオブジェクトに対して多くの弱参照を作成することは許容されます。 弱参照ごとに登録されたコールバックは、最後に登録されたコールバックから最も古い登録済みのコールバックに呼び出されます。
コールバックによって発生した例外は、標準エラー出力に記録されますが、伝播することはできません。 これらは、オブジェクトの
__del__()
メソッドから発生した例外とまったく同じ方法で処理されます。オブジェクトがハッシュ可能である場合、弱参照はハッシュ可能です。 オブジェクトが削除された後でも、ハッシュ値は維持されます。 オブジェクトが削除された後でのみ hash()が最初に呼び出された場合、呼び出しは
TypeError
を発生させます。弱参照は、同等性のテストをサポートしますが、順序付けはサポートしません。 指示対象がまだ生きている場合、2つの参照はそれらの指示対象と同じ同等関係を持ちます(コールバックに関係なく)。 いずれかの指示対象が削除されている場合、参照オブジェクトが同じオブジェクトである場合にのみ、参照は等しくなります。
バージョン2.4で変更:これはファクトリ関数ではなくサブクラス化可能な型になりました。 オブジェクトから派生します。
- weakref.proxy(object[, callback])
- 弱参照を使用するオブジェクトにプロキシを返します。 これにより、弱参照オブジェクトで使用される明示的な逆参照を要求する代わりに、ほとんどのコンテキストでプロキシの使用がサポートされます。 返されるオブジェクトのタイプは、オブジェクトが呼び出し可能かどうかに応じて、
ProxyType
またはCallableProxyType
のいずれかになります。 プロキシオブジェクトは、指示対象に関係なくハッシュ可能ではありません。 これにより、基本的に変更可能な性質に関連する多くの問題が回避され、辞書キーとしての使用が妨げられます。 callback は、 ref()関数の同じ名前のパラメーターと同じです。
- weakref.getweakrefcount(object)
- オブジェクトを参照する弱参照とプロキシの数を返します。
- weakref.getweakrefs(object)
- オブジェクトを参照するすべての弱参照およびプロキシオブジェクトのリストを返します。
- class weakref.WeakKeyDictionary([dict])
キーを弱く参照するマッピングクラス。 キーへの強い参照がなくなると、辞書のエントリは破棄されます。 これを使用すると、オブジェクトに属性を追加せずに、アプリケーションの他の部分が所有するオブジェクトに追加のデータを関連付けることができます。 これは、属性アクセスをオーバーライドするオブジェクトで特に役立ちます。
ノート
注意: WeakKeyDictionary はPythonディクショナリの上に構築されているため、反復処理するときにサイズを変更してはなりません。 WeakKeyDictionary の場合、反復中にプログラムによって実行されるアクションにより、ディクショナリ内のアイテムが「魔法によって」(ガベージコレクションの副作用として)消える可能性があるため、これを保証するのは難しい場合があります。
WeakKeyDictionary オブジェクトには、次の追加メソッドがあります。 これらは内部参照を直接公開します。 参照は、使用時に「ライブ」であることが保証されていないため、参照を呼び出した結果を使用前に確認する必要があります。 これは、ガベージコレクターが必要以上にキーを保持する原因となる参照の作成を回避するために使用できます。
- WeakKeyDictionary.iterkeyrefs()
キーへの弱参照の反復可能オブジェクトを返します。
バージョン2.5の新機能。
- WeakKeyDictionary.keyrefs()
キーへの弱参照のリストを返します。
バージョン2.5の新機能。
- class weakref.WeakValueDictionary([dict])
値を弱く参照するマッピングクラス。 値への強い参照が存在しなくなると、ディクショナリのエントリは破棄されます。
ノート
注意: WeakValueDictionary はPythonディクショナリの上に構築されているため、反復処理するときにサイズを変更してはなりません。 WeakValueDictionary の場合、反復中にプログラムによって実行されるアクションにより、ディクショナリ内のアイテムが「魔法によって」(ガベージコレクションの副作用として)消える可能性があるため、これを保証するのは難しい場合があります。
WeakValueDictionary オブジェクトには、次の追加メソッドがあります。 これらのメソッドには、 WeakKeyDictionary オブジェクトのiterkeyrefs()
およびkeyrefs()
メソッドと同じ問題があります。
- WeakValueDictionary.itervaluerefs()
値への弱参照の反復可能オブジェクトを返します。
バージョン2.5の新機能。
- WeakValueDictionary.valuerefs()
値への弱参照のリストを返します。
バージョン2.5の新機能。
- class weakref.WeakSet([elements])
要素への弱参照を保持するクラスを設定します。 要素への強い参照が存在しなくなると、要素は破棄されます。
バージョン2.7の新機能。
- weakref.ReferenceType
- 弱参照オブジェクトの型オブジェクト。
- weakref.ProxyType
- 呼び出し可能ではないオブジェクトのプロキシのタイプオブジェクト。
- weakref.CallableProxyType
- 呼び出し可能オブジェクトのプロキシの型オブジェクト。
- weakref.ProxyTypes
- プロキシのすべての型オブジェクトを含むシーケンス。 これにより、両方のプロキシタイプの名前に依存することなく、オブジェクトがプロキシであるかどうかを簡単にテストできます。
- exception weakref.ReferenceError
- プロキシオブジェクトが使用されているが、基になるオブジェクトが収集されている場合に例外が発生します。 これは、標準の ReferenceError 例外と同じです。
8.11.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 is a weak reference object
o = r()
if o is None:
# referent has been garbage collected
print "Object has been deallocated; can't frobnicate."
else:
print "Object is still live!"
o.do_something_useful()
「活性」について別のテストを使用すると、スレッド化されたアプリケーションで競合状態が発生します。 別のスレッドにより、弱参照が呼び出される前に弱参照が無効になる可能性があります。 上記のイディオムは、スレッド化されたアプリケーションだけでなく、シングルスレッド化されたアプリケーションでも安全です。
ref オブジェクトの特殊バージョンは、サブクラス化によって作成できます。 これは、 WeakValueDictionary の実装で使用され、マッピングの各エントリのメモリオーバーヘッドを削減します。 これは、追加情報を参照に関連付けるのに最も役立つ場合がありますが、参照を取得するための呼び出しに追加の処理を挿入するためにも使用できます。
この例は、 ref のサブクラスを使用して、オブジェクトに関する追加情報を格納し、指示対象にアクセスしたときに返される値に影響を与える方法を示しています。
import weakref
class ExtendedRef(weakref.ref):
def __init__(self, ob, callback=None, **annotations):
super(ExtendedRef, self).__init__(ob, callback)
self.__counter = 0
for k, v in annotations.iteritems():
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).__call__()
if ob is not None:
self.__counter += 1
ob = (ob, self.__counter)
return ob
8.11.2。 例
この簡単な例は、アプリケーションがオブジェクトIDを使用して、以前に見たオブジェクトを取得する方法を示しています。 オブジェクトのIDは、オブジェクトを強制的に存続させることなく、他のデータ構造で使用できますが、存続している場合は、IDによってオブジェクトを取得できます。
import weakref
_id2obj_dict = weakref.WeakValueDictionary()
def remember(obj):
oid = id(obj)
_id2obj_dict[oid] = obj
return oid
def id2obj(oid):
return _id2obj_dict[oid]