У меня есть некоторый код, где экземпляры классов имеют родительские <-> дочерние ссылки друг на друга, например ::
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
- но что, если я не знаю, когда это сделать?
Это подходящее время для использования модуля слабой связи? Что именно я могу слабить? атрибут parent
? Атрибут children
? Весь объект? Все вышеперечисленное? Я вижу разговоры о WeakKeyDictionary и weakref.proxy, но мне не ясно, как они должны использоваться, если вообще используются, в этом случае.
Это также на python2.4 (не может обновиться).
Обновление: пример и резюме
Какие объекты для слабой связи зависят от того, какой объект может жить без другого, и какие объекты зависят друг от друга. Объект, который живет дольше всего, должен содержать слабые ссылки на объекты с более коротким сроком службы. Точно так же слабые ссылки не должны быть сделаны для зависимостей - если они есть, зависимость может молча исчезнуть, даже если она все еще необходима.
Если, например, у вас есть древовидная структура root
, которая имеет дочерние элементы kids
, но может существовать без дочерних элементов, тогда объект root
должен использовать слабые ссылки для kids
. Это также имеет место, если дочерний объект зависит от существования родительского объекта. Ниже для дочернего объекта требуется родительский объект, чтобы вычислить его глубину, следовательно, строгий 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
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()
f1 = CliFacade(sub)
f2 = WebFacade(sub)
# Go on to reading from POST, stdin, etc