У меня есть код, в котором экземпляры классов имеют родительский ↔ дочерний элемент ссылки друг на друга, например:
class Node(object):
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, но неясно, как их следует использовать, если это вообще возможно.
Это также на python2.4 (невозможно обновить).
Обновление: пример и сводка
Какие объекты для weakref-ify зависят от того, какой объект может жить без другого, а какие объекты зависят друг от друга. Объект, который живет дольше всех, должен содержать слабые ссылки на объекты с более коротким периодом. Аналогичным образом, слабые стороны не должны быть связаны с зависимостями - если они есть, зависимость может исчезнуть молча, даже если она по-прежнему необходима.
Если, например, у вас есть древовидная структура, root
, у которой есть дети, kids
, но может существовать без детей, тогда объект root
должен использовать weakrefs для своего kids
. Это также имеет место, если дочерний объект зависит от существования родительского объекта. Ниже для дочернего объекта требуется родительский элемент, чтобы вычислить его глубину, и, следовательно, strong-ref для 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()
# do what you will with root or sub-trees of it.
Чтобы перевернуть отношения вокруг, у нас есть что-то вроде ниже. Здесь для классов Facade
требуется, чтобы экземпляр Subsystem
работал, поэтому они используют сильную ссылку на подсистему, в которой они нуждаются. Subsystem
s, однако, не требует работы Facade
. Subsystem
просто укажите способ уведомления Facade
о действиях друг друга.
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()
f1 = CliFacade(sub)
f2 = WebFacade(sub)
# Go on to reading from POST, stdin, etc