У меня есть код, в котором экземпляры классов имеют родительские-дочерние ссылки друг на друга, например:
class Node:
def __init__(self):
self.parent = None
self.children = {}
def AddChild(self, name, child):
child.parent = self
self.children[name] = child
def Run():
root, c1, c2 = Node(), Node(), Node()
root.AddChild('first', c1)
root.AddChild('second', c2)
Run()
Я думаю, что это создает циклические ссылки, так что root
, c1
и c2
не будут освобождены после завершения Run(), верно? Так как же заставить их освободиться? Я думаю, что могу сделать что-то вроде root.children.clear()
или self.parent = None
, но что, если я не знаю, когда это сделать?
Подходит ли это время для использования модуля weakref? Что именно я слаборефифицирую? атрибут parent
? Атрибут children
? Весь объект? Все вышеперечисленное? Я вижу разговоры о WeakKeyDictionary и weakref.proxy, но мне не ясно, как их следует использовать, если вообще нужно, в этом случае.
Это также на Python 2.4 (не может быть обновлено).
Обновление: пример и резюме
Какие объекты для weakref-ify зависит от того, какой объект может жить без другого, и какие объекты зависят друг от друга. Объект, который живет дольше всех, должен содержать слабые ссылки на объекты с более коротким сроком жизни. Точно так же слабые ссылки не должны быть сделаны для зависимостей - если они есть, зависимость может незаметно исчезнуть, даже если она все еще нужна.
Если, например, у вас есть древовидная структура root
, которая имеет дочерние элементы kids
, но может существовать без дочерних элементов, то объект root
должен использовать слабые ссылки для своего kids
. Это также имеет место, если дочерний объект зависит от существования родительского объекта. Ниже дочерний объект требует родителя, чтобы вычислить его глубину, отсюда и сильная ссылка для parent
. Однако члены атрибута kids
являются необязательными, поэтому для предотвращения циклической ссылки используются слабые ссылки.
class Node:
def __init__(self):
self.parent = None
self.kids = weakref.WeakValueDictionary()
def GetDepth(self):
root, depth = self, 0
while root:
depth += 1
root = root.parent
return depth
root = Node()
root.kids['one'] = Node()
root.kids['two'] = Node()
Чтобы перевернуть отношения, у нас есть что-то вроде приведенного ниже. Здесь классам Facade
для работы требуется экземпляр Subsystem
, поэтому они используют строгую ссылку на нужную им подсистему. Subsystem
s, однако, не требуют Facade
для работы. Subsystem
s просто предоставляют способ уведомлять Facade
s о действиях друг друга.
class Facade:
def __init__(self, subsystem):
self.subsystem = subsystem
subsystem.Register(self)
class Subsystem:
def __init__(self):
self.notify = []
def Register(self, who):
self.notify.append(weakref.proxy(who))
sub = Subsystem()
cli = Facade(sub)