Pythonでなんらかのクラスのコレクションのようなものを作るとき、親になっているオブジェクトの参照を持っておきたい ということはあると思います。
そんなとき、他の言語などだとときどき、owner
という変数を作って親オブジェクトの参照を持っておく などと言うことがあるのですが、そのまま実装すると循環参照となり、取得したメモリが意図したタイミングで解放されなくなることがあります。
循環参照が起こりうるコード
class ParentClass:
def __init__(self):
self.child = []
class ChildClass:
def __init__(self, owner):
self._owner = owner
p = ParentClass()
p.child.append(ChildClass(p))
# ...
こんなときのために、オブジェクトを参照する際に参照カウンタを増やさない、**弱参照(weakrefモジュール)**というものがあります。
弱参照を使ったコード
import weakref
class ParentClass:
def __init__(self):
self.child = []
class ChildClass:
def __init__(self, owner):
self._owner = weakref.ref(owner)
p = ParentClass()
p.child.append(ChildClass(p))
# ...
なお、このweakrefオブジェクトで作った参照を辿りたいときは、メソッドのように()をつけて呼び出します。
弱参照を使ったコード
import weakref
class ParentClass:
def __init__(self):
self.child = []
def message(self):
print("called")
class ChildClass:
def __init__(self, owner):
self._owner = weakref.ref(owner)
def message(self):
self._owner().message()
p = ParentClass()
p.child.append(ChildClass(p))
p.child[0].message()
# ...