"weakref" --- 弱参照
********************

**ソースコード:** Lib/weakref.py

======================================================================

"weakref" モジュールを使うと、Python プログラムからオブジェクトへの *
弱参照* を作成できます。

以下では、用語リファレント(*referent*) は弱参照が参照するオブジェクト
を意味します。

オブジェクトへの弱参照があることは、そのオブジェクトを生かしておくのに
は不十分です。リファレントへの参照が弱参照しか残っていない場合、
*garbage collection* はリファレントを自由に破棄し、メモリを別のものに
再利用することができます。しかし、オブジェクトへの強参照がなくても、オ
ブジェクトが実際に破棄されるまでは、弱参照はオブジェクトを返す場合があ
ります。

弱参照の主な用途は、巨大なオブジェクトを保持するキャッシュやマッピング
を実装することです。ここで、キャッシュやマッピングに保持されているから
という理由だけで、巨大なオブジェクトが生き続けることは望ましくありませ
ん。

例えば、大きなバイナリ画像オブジェクトがいくつもあり、それぞれに名前を
関連付けたい場合を考えます。 Python の辞書で名前を画像に、または画像を
名前に対応付けると、辞書の値やキーに含まれるという理由だけで画像オブジ
ェクトが生き続けます。 代わりに "weakref" モジュールの
"WeakKeyDictionary" と "WeakValueDictionary" を使うと、 弱参照によって
、マッピングに含まれるという理由だけではオブジェクトを生存させないマッ
ピングを構築できます。 例えば画像オブジェクトが "WeakValueDictionary"
の値である場合、 その画像への参照が弱参照マッピングの持つ弱参照だけに
なれば、ガベージコレクションはそのオブジェクトを回収でき、弱参照マッピ
ング内の対応するエントリーも削除されます。

"WeakKeyDictionary" と "WeakValueDictionary" はその実装に弱参照を使用
しており、キーや値がガーベジコレクションによって回収されたことを弱参照
辞書に通知するコールバック関数を設定しています。 "WeakSet" は "set" イ
ンターフェースを実装していますが、 "WeakKeyDictionary" のように要素へ
の弱参照を持ちます。

"finalize" は、オブジェクトのガベージコレクションの実行時にクリーンア
ップ関数が呼び出されるように登録する、単純な方法を提供します。これは、
未加工の弱参照上にコールバック関数を設定するよりも簡単です。なぜなら、
オブジェクトのコレクションが完了するまでファイナライザが生き続けること
を、モジュールが自動的に保証するからです。

ほとんどのプログラムでは、これらの弱参照コンテナ型か "finalize" のいず
れかを使うだけで十分でしょう。 通常は、弱参照を直接作成する必要はあり
ません。 "weakref" モジュールは、高度な用途のために低水準の仕組みも公
開しています。

すべてのオブジェクトを弱参照できるわけではありません。 弱参照に対応す
るオブジェクトには、クラスインスタンス、(C ではなく) Python で書かれた
関数、インスタンスメソッド、 set、frozenset、一部の *ファイルオブジェ
クト*、*ジェネレータ*、型オブジェクト、 ソケット、配列、deque、正規表
現パターンオブジェクト、コードオブジェクトがあります。

バージョン 3.2 で変更: thread.lock, threading.Lock, code オブジェクト
のサポートが追加されました。

"list" や "dict" など、いくつかの組み込み型は弱参照を直接サポートしま
せんが、以下のようにサブクラス化を行えばサポートを追加できます:

   class Dict(dict):
       pass

   obj = Dict(red=1, green=2, blue=3)   # このオブジェクトは弱参照できる

"tuple" や "int" など、他の組み込み型はサブクラス化しても弱参照をサポ
ートしません。

拡張型は、簡単に弱参照をサポートできます。詳細については、 弱参照(Weak
Reference)のサポート を参照してください。

When "__slots__" are defined for a given type, weak reference support
is disabled unless a "'__weakref__'" string is also present in the
sequence of strings in the "__slots__" declaration. See __slots__
documentation for details.

class weakref.ref(object[, callback])

   *object* への弱参照を返します。 リファレントがまだ生きていれば、参
   照オブジェクトを呼び出すことで元のオブジェクトを取り出せます。 リフ
   ァレントが生きていなければ、参照オブジェクトを呼び出すと "None" が
   返ります。 *callback* に "None" 以外の値が指定され、返された弱参照
   オブジェクトがまだ生きている場合、リファレントの後始末処理の直前に
   コールバックが呼び出されます。 コールバックには弱参照オブジェクトが
   唯一の引数として渡されますが、その時点でリファレントは利用できませ
   ん。

   同じオブジェクトに対してたくさんの弱参照を作れます。それぞれの弱参
   照に対して登録されたコールバックは、もっとも新しく登録されたコール
   バックからもっとも古いものへと呼び出されます。

   コールバックで発生した例外は標準エラー出力に表示されますが、呼び出
   し元には伝播しません。 オブジェクトの "__del__()" メソッドで発生し
   た例外とまったく同じように扱われます。

   *object* が *ハッシュ可能* ならば、弱参照はハッシュ可能です。それら
   は *object* が削除された後でもそれらのハッシュ値を保持します。
   *object* が削除されてから初めて "hash()" が呼び出された場合に、その
   呼び出しは "TypeError" を発生させます。

   弱参照は等価性のテストをサポートしていますが、順序をサポートしてい
   ません。 リファレントがまだ生きているならば、 *callback* に関係なく
   二つの参照はそれらのリファレントと同じ等価関係を持ちます。 リファレ
   ントのどちらか一方が削除された場合、参照オブジェクトが同一である場
   合に限り、その参照は等価です。

   これはファクトリ関数ではなく、サブクラス化可能な型です。

   弱参照は、参照するオブジェクトの型を引数とする ジェネリック です。

   __callback__

      この読み出し専用の属性は、現在弱参照に関連付けられているコールバ
      ックを返します。コールバックが存在しないか、弱参照のリファレント
      が生きていない場合、この属性の値は "None"  になります。

   バージョン 3.4 で変更: "__callback__" 属性が追加されました。

weakref.proxy(object[, callback])

   弱参照を使う *object* へのプロキシを返します。弱参照オブジェクトを
   明示的な参照外しをしながら利用する代わりに、多くのケースでプロキシ
   を利用することができます。返されるオブジェクトは、 *object* が呼び
   出し可能かどうかによって、 "ProxyType" または "CallableProxyType"
   のどちらかの型を持ちます。プロキシオブジェクトはリファレントに関係
   なく *ハッシュ可能* ではありません。これによって、それらの基本的な
   変更可能という性質による多くの問題を避けています。そして、辞書のキ
   ーとしての利用を妨げます。 *callback* は "ref()" 関数の同じ名前のパ
   ラメータと同じものです。(--- 訳注: リファレントが変更不能型であって
   も、プロキシはリファレントが消えるという状態の変更があるために、変
   更可能型です。---)

   リファレントがガベージコレクションで回収された後にプロキシオブジェ
   クトの属性にアクセスすると、"ReferenceError" が発生します。

   バージョン 3.8 で変更: プロキシオブジェクトで使える演算子に、行列乗
   算演算子 "@" と "@=" を追加しました。

weakref.getweakrefcount(object)

   *object* を参照する弱参照とプロキシの数を返します。

weakref.getweakrefs(object)

   *object* を参照するすべての弱参照とプロキシオブジェクトのリストを返
   します。

class weakref.WeakKeyDictionary([dict])

   キーを弱参照するマッピングクラス。キーへの強参照がなくなったときに
   、辞書のエントリは捨てられます。アプリケーションの他の部分が所有す
   るオブジェクトへ属性を追加することもなく、それらのオブジェクトに追
   加データを関連づけるために使うことができます。これは属性へのアクセ
   スをオーバーライドするオブジェクトに特に便利です。

   既存のキーと等しい値を持つ別のオブジェクトをキーとして辞書に挿入す
   ると、値は置き換わりますが、既存のキーは置き換わりません。 そのため
   、元のキーへの参照を削除すると、辞書のエントリーも削除されます。

      >>> class T(str): pass
      ...
      >>> k1, k2 = T(), T()
      >>> d = weakref.WeakKeyDictionary()
      >>> d[k1] = 1   # d = {k1: 1}
      >>> d[k2] = 2   # d = {k1: 2}
      >>> del k1      # d = {}

   再代入する前にキーを削除すれば回避できます。

      >>> class T(str): pass
      ...
      >>> k1, k2 = T(), T()
      >>> d = weakref.WeakKeyDictionary()
      >>> d[k1] = 1   # d = {k1: 1}
      >>> del d[k1]
      >>> d[k2] = 2   # d = {k2: 2}
      >>> del k1      # d = {k2: 2}

   バージョン 3.9 で変更: **PEP 584** で規定されている "|" 演算子と
   "|=" 演算子のサポートを追加しました。

"WeakKeyDictionary" オブジェクトには、内部の弱参照を直接公開する追加の
メソッドがあります。 その参照先が利用時にも生きている保証はないため、
弱参照を呼び出した結果を確認してから使用する必要があります。 このメソ
ッドを使うと、キーを必要以上に長く生存させる参照を作らずに済みます。

WeakKeyDictionary.keyrefs()

   キーへの弱参照を持つ iterable オブジェクトを返します。

class weakref.WeakValueDictionary([dict])

   値を弱参照するマッピングクラス。値への強参照が存在しなくなったとき
   に、辞書のエントリは捨てられます。

   バージョン 3.9 で変更: **PEP 584** で規定されている "|" 演算子と
   "|=" 演算子のサポートを追加しました。

"WeakValueDictionary" オブジェクトには、"WeakKeyDictionary.keyrefs()"
メソッドと同じ注意点を持つ追加のメソッドがあります。

WeakValueDictionary.valuerefs()

   値への弱参照を持つ iterable オブジェクトを返します。

class weakref.WeakSet([elements])

   要素への弱参照を持つ集合型。要素への強参照が無くなったときに、その
   要素は削除されます。

class weakref.WeakMethod(method[, callback])

   束縛されたメソッド (クラスで定義され、インスタンスから取得されるメ
   ソッド) への弱参照をシミュレートする、"ref" のカスタムサブクラスで
   す。 束縛されたメソッドは短命なので、通常の弱参照では保持し続けられ
   ません。 "WeakMethod" には、オブジェクトまたは元の関数のどちらか一
   方が破棄されるまで、束縛されたメソッドを再作成するための特別なコー
   ドがあります。

      >>> class C:
      ...     def method(self):
      ...         print("method called!")
      ...
      >>> c = C()
      >>> r = weakref.ref(c.method)
      >>> r()
      >>> r = weakref.WeakMethod(c.method)
      >>> r()
      <bound method C.method of <__main__.C object at 0x7fc859830220>>
      >>> r()()
      method called!
      >>> del c
      >>> gc.collect()
      0
      >>> r()
      >>>

   *callback* は "ref()" 関数の同名のパラメータと同じです。

   Added in version 3.4.

class weakref.finalize(obj, func, /, *args, **kwargs)

   *obj* がガベージコレクションで回収されるときに呼び出される、呼び出
   し可能なファイナライザオブジェクトを返します。 通常の弱参照とは異な
   り、ファイナライザは参照しているオブジェクトが回収されるまで必ず生
   き残り、そのおかげでライフサイクル管理が大いに簡単になります。

   ファイナライザは (直接もしくはガベージコレクションのときに) 呼び出
   されるまで *生きている* と見なされ、呼び出された後には *死んでいま
   す* 。 生きているファイナライザを呼び出すと、 "func(*arg,
   **kwargs)" を評価した結果を返します。一方、死んでいるファイナライザ
   を呼び出すと "None" を返します。

   ガベージコレクション中にファイナライザのコールバックで発生した例外
   は標準エラー出力に表示されますが、呼び出し元には伝播しません。 オブ
   ジェクトの "__del__()" メソッドや弱参照のコールバックで発生した例外
   と同じように扱われます。

   プログラム終了時 (より一般には *インタープリタのシャットダウン* 時)
   に、 残っている生存中のファイナライザは、"atexit" 属性が偽に設定さ
   れていない限り、それぞれ呼び出されます。 呼び出し順は作成順の逆です
   。

   *インタープリタのシャットダウン* の後半では、モジュールのグローバル
   変数が "None" に置き換えられている可能性があります。 ファイナライザ
   は、この段階では決してコールバックを呼び出しません。

   __call__()

      *self* が生きている場合は、死んだ状態にして "func(*args,
      **kwargs)" の呼び出し結果を返します。 *self* が死んでいる場合は
      "None" を返します。

   detach()

      *self* が生きている場合は、死んだ状態にしてタプル "(obj, func,
      args, kwargs)" を返します。 *self* が死んでいる場合は "None" を
      返します。

   peek()

      *self* が生きている場合は、タプル "(obj, func, args, kwargs)" を
      返します。 *self* が死んでいる場合は "None" を返します。

   alive

      ファイナライザが生きている場合には真、そうでない場合には偽のプロ
      パティです。

   atexit

      書き込み可能なブール値のプロパティで、デフォルトは真です。 *イン
      タープリタのシャットダウン* 時には、 生存中で "atexit" が真のフ
      ァイナライザがすべて、作成順の逆に呼び出されます。

   注釈:

     *func*、*args*、*kwargs* が、直接にも間接にも *obj* への参照を持
     たないことが重要です。 参照を持っていると、*obj* はガベージコレク
     ションで回収されなくなります。 特に、*func* を *obj* の束縛された
     メソッドにしてはいけません。

   Added in version 3.4.

class weakref.ReferenceType

   弱参照オブジェクトのための型オブジェクト。

class weakref.ProxyType

   呼び出し可能でないオブジェクトのプロキシのための型オブジェクト。

class weakref.CallableProxyType

   呼び出し可能なオブジェクトのプロキシのための型オブジェクト。

weakref.ProxyTypes

   プロキシのためのすべての型オブジェクトを含むシーケンス。これは両方
   のプロキシ型の名前付けに依存しないで、オブジェクトがプロキシかどう
   かのテストをより簡単にできます。

参考:

  **PEP 205** - 弱参照
     この機能の提案と理論的根拠。初期の実装と他の言語における類似の機
     能についての情報へのリンクを含んでいます。


弱参照オブジェクト
==================

弱参照オブジェクトにはメソッドはなく、"ref.__callback__" 以外の属性も
ありません。 弱参照オブジェクトを呼び出すと、リファレントがまだ存在し
ていれば取得できます:

>>> 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 deallocated; can't frobnicate.")
   else:
       print("Object is still live!")
       o.do_something_useful()

"生存性(liveness)"のテストを分割すると、スレッド化されたアプリケーショ
ンにおいて競合状態を作り出します。 (訳注:"if r() is not None:
r().do_something()" では、2度目のr()がNoneを返す可能性があります) 弱参
照が呼び出される前に、他のスレッドは弱参照が無効になる原因となり得ます
。上で示したイディオムは、シングルスレッドのアプリケーションと同じくマ
ルチスレッド化されたアプリケーションにおいても安全です。

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

以下の例は、"ref" のサブクラスを使ってオブジェクトに関する追加情報を保
存し、 リファレントへのアクセス時に返す値を変更する方法を示しています
。

   import weakref

   class ExtendedRef(weakref.ref):
       def __init__(self, ob, callback=None, /, **annotations):
           super().__init__(ob, callback)
           self.__counter = 0
           for k, v in annotations.items():
               setattr(self, k, v)

       def __call__(self):
           """リファレントと、この参照が呼び出された回数のペアを返す。
           """
           ob = super().__call__()
           if ob is not None:
               self.__counter += 1
               ob = (ob, self.__counter)
           return ob


使用例
======

この簡単な例では、アプリケーションが以前に参照したオブジェクトを、オブ
ジェクト 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]


ファイナライザオブジェクト
==========================

"finalize" を使う主な利点は、返されたファイナライザオブジェクトを保持
せずに、簡単にコールバックを登録できることです。 例えば次のようになり
ます。

>>> import weakref
>>> class Object:
...     pass
...
>>> kenny = Object()
>>> weakref.finalize(kenny, print, "You killed Kenny!")
<finalize object at ...; for 'Object' at ...>
>>> del kenny
You killed Kenny!

ファイナライザは直接呼び出すこともできます。ただし、ファイナライザはコ
ールバックを最大でも一度しか呼び出しません。

>>> def callback(x, y, z):
...     print("CALLBACK")
...     return x + y + z
...
>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> assert f.alive
>>> assert f() == 6
CALLBACK
>>> assert not f.alive
>>> f()                     # callback not called because finalizer dead
>>> del obj                 # callback not called because finalizer dead

"detach()" メソッドでファイナライザの登録を解除できます。 ファイナライ
ザは死んだ状態になり、作成時にコンストラクタへ渡した引数が返されます。

>>> obj = Object()
>>> f = weakref.finalize(obj, callback, 1, 2, z=3)
>>> f.detach()
(<...Object object ...>, <function callback ...>, (1, 2), {'z': 3})
>>> newobj, func, args, kwargs = _
>>> assert not f.alive
>>> assert newobj is obj
>>> assert func(*args, **kwargs) == 6
CALLBACK

"atexit" 属性を "False" に設定しない限り、ファイナライザがまだ生きてい
ればプログラム終了時に呼び出されます。 例えば次のようになります。

   >>> obj = Object()
   >>> weakref.finalize(obj, print, "obj dead or exiting")
   <finalize object at ...; for 'Object' at ...>
   >>> exit()
   obj dead or exiting


ファイナライザと "__del__()" メソッドの比較
===========================================

インスタンスが一時ディレクトリを表す、クラスを作成するとします。そのデ
ィレクトリは、次のイベントのいずれかが起きた時に、そのディレクトリの内
容とともに削除されるべきです。

* オブジェクトのガベージコレクションが行われた場合

* オブジェクトの "remove()" メソッドが呼び出される、または

* プログラムが終了した場合

"__del__()" メソッドを使って、以下のようにクラスを実装しようとするかも
しれません。

   class TempDir:
       def __init__(self):
           self.name = tempfile.mkdtemp()

       def remove(self):
           if self.name is not None:
               shutil.rmtree(self.name)
               self.name = None

       @property
       def removed(self):
           return self.name is None

       def __del__(self):
           self.remove()

Starting with Python 3.4, "__del__()" methods no longer prevent
reference cycles from being garbage collected, and module globals are
no longer forced to "None" during *interpreter shutdown*. So this code
should work without any issues on CPython.

ただし、"__del__()" メソッドの扱いは、インタープリタのガベージコレクタ
の内部実装に依存するため、実装ごとの差が大きいことが知られています。

より堅牢な方法として、オブジェクトの状態全体にアクセスする代わりに、
必要な特定の関数やオブジェクトだけを参照するファイナライザを定義できま
す。

   class TempDir:
       def __init__(self):
           self.name = tempfile.mkdtemp()
           self._finalizer = weakref.finalize(self, shutil.rmtree, self.name)

       def remove(self):
           self._finalizer()

       @property
       def removed(self):
           return not self._finalizer.alive

このように定義すると、ファイナライザが受け取る参照は、ディレクトリを適
切に削除するために必要なものだけになります。 オブジェクトがガベージコ
レクションで回収されない場合でも、終了時にファイナライザが呼び出されま
す。

弱参照を使ったファイナライザのもう 1 つの利点は、第三者が定義を管理す
るクラスにもファイナライザを登録できることです。 例えば、モジュールが
アンロードされたときにコードを実行できます。

   import weakref, sys
   def unloading_module():
       # implicit reference to the module globals from the function body
   weakref.finalize(sys.modules[__name__], unloading_module)

注釈:

  プログラムが終了する直前にデーモンスレッド内でファイナライザオブジェ
  クトを作成すると、終了時に呼び出されない可能性があります。 ただし、
  デーモンスレッド内では "atexit.register()"、"try: ... finally: ..."
  、"with: ..." もクリーンアップの実行を保証しません。
