I have some code where instances of classes have parent<->child references to each other, e.g.:
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()
I think this creates circular references such that root
, c1
and c2
won't be freed after Run() is completed, right?. So, how do get them to be freed? I think I can do something like root.children.clear()
, or self.parent = None
- but what if I don't know when to do that?
Is this an appropriate time to use the weakref module? What, exactly, do I weakref'ify? the parent
attribute? The children
attribute? The whole object? All of the above? I see talk about the WeakKeyDictionary and weakref.proxy, but its not clear to me how they should be used, if at all, in this case.
This is also on python2.4 (can't upgrade).
Update: Example and Summary
What objects to weakref-ify depends on which object can live without the other, and what objects depend on each other. The object that lives the longest should contain weakrefs to the shorter-lived objects. Similarly, weakrefs should not be made to dependencies - if they are, the dependency could silently disappear even though it is still needed.
If, for example, you have a tree structure, root
, that has children, kids
, but can exist without children, then the root
object should use weakrefs for its kids
. This is also the case if the child object depends on the existence of the parent object. Below, the child object requires a parent in order to compute its depth, hence the strong-ref for parent
. The members of the kids
attribute are optional, though, so weakrefs are used to prevent a circular reference.
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 count
root = Node()
root.kids["one"] = Node()
root.kids["two"] = Node()
# do what you will with root or sub-trees of it.
To flip the relationship around, we have something like the below. Here, the Facade
classes require a Subsystem
instance to work, so they use a strong-ref to the subsystem they need. Subsystem
s, however, don't require a Facade
to work. Subsystem
s just provide a way to notify Facade
s about each other's actions.
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