How and when to appropriately use weakref in Python

Yep, weakref's excellent here. Specifically, instead of:

self.children = {}

use:

self.children = weakref.WeakValueDictionary()

Nothing else needs change in your code. This way, when a child has no other differences, it just goes away -- and so does the entry in the parent's children map that has that child as the value.

Avoiding reference loops is up high on a par with implementing caches as a motivation for using the weakref module. Ref loops won't kill you, but they may end up clogging your memory, esp. if some of the classes whose instances are involved in them define __del__, since that interferes with the gc's module ability to dissolve those loops.


I suggest using child.parent = weakref.proxy(self). This is a good solution to avoid circular references when the lifetime of parent covers the lifetime of child. Use self.children = weakref.WeakValueDictionary() (as Alex Martelli suggested) when the lifetime of child covers the lifetime of parent. But never use weak references when both parent and child can be alive independently. Here after these rules are illustrated with examples.

Use a weakly referenced parent if you bind the root to a name and pass it around, while children are accessed from it:

def Run():
    root, c1, c2 = Node(), Node(), Node()
    root.AddChild('first', c1)
    root.AddChild('second', c2)
    return root  # only root refers to c1 and c2 after return, 
                 # so this references should be strong

Use weakly referenced children if you bind each child to a name and pass them around, while root is accessed from them:

def Run():
    root, c1, c2 = Node(), Node(), Node()
    root.AddChild('first', c1)
    root.AddChild('second', c2)
    return c1, c2

Don’t use weak references in this case:

def Run():
    root, c1, c2 = Node(), Node(), Node()
    root.AddChild('first', c1)
    root.AddChild('second', c2)
    return c1