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

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

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

"weakref" モジュールは、Pythonプログラマがオブジェクトへの弱参照
(*weak refarence*)を作成できるようにします。

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

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

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

例えば、巨大なバイナリ画像のオブジェクトがたくさんあり、それぞれに名前
を関連付けたいとします。 Python の辞書型を使って名前を画像に対応付けた
り画像を名前に対応付けたりすると、画像オブジェクトは辞書内のキーや値に
使われているため存続しつづけることになります。 "weakref" モジュールが
提供している "WeakKeyDictionary" や "WeakValueDictionary" クラスはその
代用で、対応付けを構築するのに弱参照を使い、キャッシュやマッピングに存
在するという理由だけでオブジェクトを存続させないようにします。例えば、
もしある画像オブジェクトが "WeakValueDictionary" の値になっていた場合
、最後に残った画像オブジェクトへの参照を弱参照マッピングが保持していれ
ば、ガーベジコレクションはこのオブジェクトを再利用でき、画像オブジェク
トに対する弱参照内の対応付けは削除されます。

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

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

ほとんどのプログラムでは弱参照コンテナまたは "finalize" のどれかを使え
ば必要なものは揃うはずです。通常は直接自前の弱参照を作成する必要はあり
ません。低レベルな機構は、より進んだ使い方をするために "weakref" モジ
ュールとして公開されています。

全てのオブジェクトが弱参照で参照できるわけではありません; 弱参照で参照
できるのは、クラスインスタンス、(C ではなく) Python で書かれた関数、イ
ンスタンスメソッド、set オブジェクト、frozenset オブジェクト、 *file
オブジェクト* 、 *generators* 型のオブジェクト、socket オブジェクト、
array オジェクト、deque オブジェクト、正規表現パターンオブジェクト、
code オブジェクトです。

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

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

   class Dict(dict):
       pass

   obj = Dict(red=1, green=2, blue=3)   # this object is weak referenceable

**CPython implementation detail:** "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" 以外の値を与えた場合、オブ
   ジェクトをまさに後始末処理しようとするときに呼び出します。このとき
   弱参照オブジェクトは *callback* の唯一のパラメタとして渡されます。
   リファレントはもはや利用できません。

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

   コールバックが発生させた例外は標準エラー出力に書き込まれますが、伝
   播されません。それらはオブジェクトの "__del__()" メソッドが発生させ
   る例外と完全に同じ方法で処理されます。

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

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

   これはサブクラス化可能な型というよりファクトリ関数です。

   __callback__

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

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

weakref.proxy(object[, callback])

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

   バージョン 3.8 で変更: Extended the operator support on proxy
   objects to include the matrix multiplication operators "@" and
   "@=".

weakref.getweakrefcount(object)

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

weakref.getweakrefs(object)

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

class weakref.WeakKeyDictionary([dict])

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

   バージョン 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)

   拡張された "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()
      >>>

   バージョン 3.4 で追加.

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

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

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

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

   プログラムが終了するとき、生き残ったそれぞれのファイナライザは、自
   身の "atexit" 属性が偽に設定されるまで呼び出され続けます。 ファイナ
   ライザは生成された順序の逆順で呼び出されます。

   A finalizer will never invoke its callback during the later part of
   the *interpreter shutdown* when module globals are liable to have
   been replaced by "None".

   __call__()

      If *self* is alive then mark it as dead and return the result of
      calling "func(*args, **kwargs)".  If *self* is dead then return
      "None".

   detach()

      If *self* is alive then mark it as dead and return the tuple
      "(obj, func, args, kwargs)".  If *self* is dead then return
      "None".

   peek()

      If *self* is alive then return the tuple "(obj, func, args,
      kwargs)".  If *self* is dead then return "None".

   alive

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

   atexit

      A writable boolean property which by default is true.  When the
      program exits, it calls all remaining live finalizers for which
      "atexit" is true.  They are called in reverse order of creation.

   注釈:

     It is important to ensure that *func*, *args* and *kwargs* do not
     own any references to *obj*, either directly or indirectly, since
     otherwise *obj* will never be garbage collected.  In particular,
     *func* should not be a bound method of *obj*.

   バージョン 3.4 で追加.

weakref.ReferenceType

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

weakref.ProxyType

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

weakref.CallableProxyType

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

weakref.ProxyTypes

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

参考:

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


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

Weak reference objects have no methods and no attributes besides
"ref.__callback__". A weak reference object allows the referent to be
obtained, if it still exists, by calling it:

>>> 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()

"生存性(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):
           """Return a pair containing the referent and the number of
           times the reference has been called.
           """
           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]


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

The main benefit of using "finalize" is that it makes it simple to
register a callback without needing to preserve the returned finalizer
object.  For instance

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

You can unregister a finalizer using its "detach()" method.  This
kills the finalizer and returns the arguments passed to the
constructor when it was created.

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

Unless you set the "atexit" attribute to "False", a finalizer will be
called when the program exits if it is still alive.  For instance

   >>> 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.

However, handling of "__del__()" methods is notoriously implementation
specific, since it depends on internal details of the interpreter's
garbage collector implementation.

A more robust alternative can be to define a finalizer which only
references the specific functions and objects that it needs, rather
than having access to the full state of the object:

   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

Defined like this, our finalizer only receives a reference to the
details it needs to clean up the directory appropriately. If the
object never gets garbage collected the finalizer will still be called
at exit.

The other advantage of weakref based finalizers is that they can be
used to register finalizers for classes where the definition is
controlled by a third party, such as running code when a module is
unloaded:

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

注釈:

  If you create a finalizer object in a daemonic thread just as the
  program exits then there is the possibility that the finalizer does
  not get called at exit.  However, in a daemonic thread
  "atexit.register()", "try: ... finally: ..." and "with: ..." do not
  guarantee that cleanup occurs either.
