python weakrefの理解

2272 ワード

class Node(object):

    def __init__(self, data):
        self.data = data
        self.parent = None
        self.children = []

    def add_child(self, child):
        self.children.append(child)
        child.parent = self

    def __del__(self):
        print '__del__'

n = Node(0)
del n
# __del__
n1 = Node(1)
n2 = Node(2)
n1.add_child(n2)
del n1 # no output
n2.parent
# <__main__.node at="">


親ノードのポインタは子供ノードを指し、子供ノードは親ノードを指します.これは循環参照を構成するため、オブジェクトごとの参照数が0になることはありません.
gcモジュールを手動で使用してゴミ回収を行うことができます
import gc

gc.collect()


残念なことに、ここで循環参照するオブジェクトは__del__メソッドを実現しています.gcモジュールは、どのオブジェクトの__del__メソッドを先に呼び出すべきか分からないため、これらのオブジェクトを破棄しません.gcモジュールは、このようなオブジェクトをgcに配置する.garbageでは、オブジェクトは破棄されません.
n1 = Node(1)
n2 = Node(2)
print n1, n2
# <__main__.node object="" at=""> <__main__.node object="" at="">
n1.add_child(n2)
del n1
del n2
gc.collect()
# 64
gc.garbage
# [<__main__.node object="" at=""> <__main__.node object="" at="">]


Weakrefで解決できます.オブジェクトに弱い参照が1つしか残っていない場合は、ゴミ回収できます.
import weakref

class Node(object):

    def __init__(self, data):
        self.data = data
        self._parent = None
        self.children = []

    @property
    def parent(self):
        return None if self._parent is None else self._parent()

    @parent.setter
    def parent(self, node):
        self._parent = weakref.ref(node, callback)

    def add_child(self, child):
        self.children.append(child)
        child.parent = self

def callback(ref):
    print '__del__', ref

n1 = Node(0)
n2 = Node(2)
print n1,n2
# <__main__.node object="" at=""> <__main__.node object="" at="">
n1.add_child(n2)
del n1
# __del__ 


しかし、weakrefを使用すると.ref()は弱い参照を作成し、使用するたびにxx()のように取得する必要があり、少し違和感があります.weakref.proxy()は、()操作を避けるために使用されます.
n = Node(10)
p = weakref.proxy(n)
p.data
# 10