[ACCEPTED]-How and when to appropriately use weakref in Python-circular-reference

Accepted answer
Score: 33

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

self.children = {}

use:

self.children = weakref.WeakValueDictionary()

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

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

Score: 21

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

Use a weakly referenced 6 parent if you bind the root to a name and 5 pass it around, while children are accessed 4 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 3 you bind each child to a name and pass them 2 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 1 use weak references in this case:

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

I wanted to clarify which references can 34 be weak. The following approach is general, but 33 I use the doubly-linked tree in all examples.

Logical 32 Step 1.

You need to ensure that there are 31 strong references to keep all the objects 30 alive as long as you need them. It could 29 be done in many ways, for example by:

  • [direct names]: a named reference to each node in the tree
  • [container]: a reference to a container that stores all the nodes
  • [root + children]: a reference to the root node, and references from each node to its children
  • [leaves + parent]: references to all the leaf nodes, and references from each node to its parent

Logical 28 Step 2.

Now you add references to represent 27 information, if required.

For instance, if 26 you used [container] approach in Step 1, you 25 still have to represent the edges. An edge 24 between nodes A and B can be represented 23 with a single reference; it can go in either 22 direction. Again, there are many options, for 21 example:

  • [children]: references from each node to its children
  • [parent]: a reference from each node to its parent
  • [set of sets]: a set containing 2-element sets; each 2-element contains references to nodes of one edge

Of course, if you used [root + children] approach 20 in Step 1, all your information is already 19 fully represented, so you skip this step.

Logical 18 Step 3.

Now you add references to improve 17 performance, if desired.

For instance, if 16 you used [container] approach in Step 1, and 15 [children] approach in Step 2, you might 14 desire to improve the speed of certain algorithms, and 13 add references between each each node and 12 its parent. Such information is logically 11 redundant, since you could (at a cost in 10 performance) derive it from existing data.


All the references in Step 1 must be strong.

All the references in Steps 2 and 3 may be weak or strong. There 9 is no advantage to using strong references. There 8 is an advantage to using weak references 7 until you know that cycles are no longer 6 possible. Strictly speaking, once you know 5 that cycles are impossible, it makes no 4 difference whether to use weak or strong 3 references. But to avoid thinking about 2 it, you might as well use exclusively weak 1 references in the Steps 2 and 3.

More Related questions