Proper Parenting

I’m a stickler for proper object management. I started my object hierarchy building with boost::shared_ptr in C++, and was really taken with Resource Acquisition Is Initialization (RAII) in terms of memory management. My first foray into hierarchical structures yielded a simple pattern: an object in the structure would have a weak pointer to it’s parent and strong pointers to its children.

This pattern should be fairly obvious: when an object is deleted, its children should be deleted also. This requires that the parent own its children. When it comes to the parent, however, if an object owned it’s parent as well as being owned by it, why, that would be absolutely crazy. Imagine how bizarre the custody battles would be. This is called a circular reference, and it is an issue in compiled languages. To prevent it, the child has only a weak reference to its parent, keeping order in the digital family.

In C++, the boost pointer libraries made this very easy:

// This is not the complete code for a class
class Item {
    typedef boost::weak_ptr<Item> WeakPtr;
    typedef boost::shared_ptr<Item> SharedPtr;
    typedef std::vector<SharedPtr> ChildArray;

    WeakPtr _parent;
    ChildArray _children;

In Python, every pointer is like the shared_ptr – that is, while the object is being pointed to, it is never garbage collected. When I began working hardcore in Python, I found a number of object hierarchies that used standard Python pointers to maintain parent/child relationships. In older versions of Python, this would result in memory leaks and slow performance. Python has been updated to deal with circular references, but I regard it as poor programming practice, inviting trouble. But how to avoid it?

Enter the weakref module. It allows the creation of weak pointers in Python. To implement the Python version of the C++ class, it can be used to handle the parent:

import weakref

class Item(object):
    def __init__(self, parent=None):
        self._parent = weakref.proxy(parent) if parent else None
        self._children = []

    def getParent(self):
        return self._parent

    def getChildren(self):
        return self._children

Now we’re talking – saving Python from itself, maybe saving the world – depends on what you’re writing. Regardless, you can rest assured you won’t introduce any leaking or extra CPU lag into your application.

Proper Parenting