WeakDict's

1 Function

WeakDict (Weak Dictionaries) have been designed to address CPythons problems with cyclic references (cyclic structures cannot be garbaged collected by CPythons reference counting scheme). More precisely, WeakDict's allow the realization of weak references, references that are NOT counted in the reference count and can therefore be used to build cyclic structures without obstructing the reference counting scheme.

WeakDict's are very similar to normal Python dictionaries, with the following essential exceptions:

WeakDict's have an asymptotic timing efficiency similar to normal Python dicts. Deletion of WeakValue's can take linear time in the number of uses in WeakDict's.

The implementation is mostly in the Python module weakdict with some functions realized in _weakdict.c.

2 Download

3 Example

In this example, a tree class is shown, where each tree node has a list of children and a parent reference. WeakDict's are used to implement the parent reference to avoid (strong) cycles between parent and child. Such cycles would prevent the memory reclamation of the tree by CPythons reference counting garbage collector.
from weakdict import WeakValue, WeakDict

class TreeNode(WeakValue):
  """a tree node with list of children and parent reference."""

  _children= _parent= None
  
  def __init__(self): # would usually have more parameters
    WeakValue.__init__(self)
    
  def getChildren(self):
    """returns children tuple of *self*."""
    children= self._children
    if children is None: return ()
    return tuple(children)

  def getParent(self):
    """returns parent of *self*; 'None' if there is no parent."""
    p= self._parent
    if p is None: return None
    else:
      # p is a WeakDict
      return p.get('parent')

  def insertBefore(self,node,before=None):
    """inserts *node* as child before *before*; if *before* in 'None',
    *node* becomes the last child."""
    children= self._children
    if children is None: children= self._children= []
    if before is None: children.append(node)
    else:
      i= children.index(before)
      children.insert(i,node)
    node._setParent(self)

  def _setParent(self,parent):
    """sets the parent reference to *parent*.

    A WeakDict is used to represent the reference in order to avoid cycles.
    """
    parentref= self._parent
    if parentref is None: parentref= self._parent= WeakDict()
    parentref['parent']= parent


def Main():
  """Build a tree, get reference to a leaf, then kill the tree."""
  root= TreeNode()
  innerNode= TreeNode(); root.insertBefore(innerNode,None)
  leaf= TreeNode(); innerNode.insertBefore(leaf,None)
  print "the tree is a chain of 3 elements: root, innernode, leaf"
  print 'leaf.getParent(), innerNode:', leaf.getParent(), innerNode
  print 'innerNode.getParent(), root:', innerNode.getParent(), root
  print "del root: innernode looses its parent"
  del root
  print 'innerNode.getParent():', innerNode.getParent()
  print "del innerNode: leaf looses its parent"
  del innerNode
  print 'leaf.getParent():', leaf.getParent()


if __name__ == '__main__':
  Main()

4 Versions

0.02

Dieter Maurer
Last modified: Mon May 10 21:52:43 /etc/localtime 1999