0

I'm defining some objects that essentially have list attributes that can point to each other. For instance,

class Child(object):
    def __init__(self, parents=[]):
        self.name = name
        self.parents = parents

class Parent(object):
    def __init__(self, children=[]):
        self.name = name
        self.children = children

Being relatively new to python, I'm wondering if there's an elegant way of ensuring that when a parent is added to a child's parents list, the child is automatically added to the parent's children list. Similarly when I remove a parent from a child's parents list, the child reference should be removed from the children attribute of the parent.

So far I've resorted to special methods to add and remove instances of the other class type.

For instance,

class Child(object):
    def __init__(self, parents=[]):
        self.name = name
        self.parents = parents

    def addParent(self, parent):
        if isinstance(parent, Parent) and parent not in self.parents:
            if self not in parent.children:
                parent.children.append(self)
            self.parents.append(parent)

etc..

It's working, but I'm hoping that I can possibly subclass the list object and manage this under the hood so that, a) someone unfamiliar with the object can simply use the standard list methods on the attribute without worrying about these special class dependencies, and b) i can learn how to emulate a container type.

I read another post about subclassing the list type, albeit for a more complex situation with mutating attributes and callbacks.

How to handle innerclass attribute dependencies?

Would this be a good starting point or am I better off simply creating methods as shown above to add, remove to respective list attributes?

EDIT:

To be clear, I'm not a programmer, so what may seem obvious in your comments is not necessarily the case to me. I'm researching and appreciate the feedback.

With the example above I tried sub-classing list:

class LinkedParentList(list):
    def __init__(self, container=None):
        super(LinkedParentList, self).__init__(self)
        self._container = container

    def __setitem__(self, index, value):
        if self._container not in value.children:
            value.children.append(self._container)
            print 'Adding to LinkedParentList'
        super(LinkedParentList, self).__setitem__(index, value)

    def __delitem__(self, index):
        item = self.__getitem__(index)
        if self._container in item.children:
            item.children.remove(self._container)
        super(LinkedParentList, self).__delitem__(index)

And in my original Child class:

class Child(object):
    def __init__(self, parents=None):
        self.name = name
        self.parents = LinkedParentList(self)

This however doesn't seem to work, in fact the setitem and delitem are not printing. Should I instead be overriding append, remove directly?

Community
  • 1
  • 1
Klaudikus
  • 382
  • 3
  • 12
  • 6
    Careful. Usually having a mutable default argument is a bad thing...http://stackoverflow.com/q/1132941/748858 – mgilson Jun 18 '14 at 03:09
  • Subclassing `list` seems easiest. You'll have to [override some methods](https://docs.python.org/2/reference/datamodel.html#emulating-container-types) and have your Parent class as a nice composite object, without the need for `isinstance`. – 9000 Jun 18 '14 at 03:10
  • @9000 -- There's also `collections.MutableSequence` which can be used to create a list-like object as well. – mgilson Jun 18 '14 at 03:12
  • @9000 -- Given that I'm new to python, I'm not sure I understand when you mention using the Parent class as a nice composite object... – Klaudikus Jun 18 '14 at 13:16
  • @Klaudikus: it's not Python-specific: 'prefer composition to inheritance'. Instead of different `Parent` classes _inheriting_ the implementation that sets back-links in the inserted items, you _compose_ your object from self-contained parts, e.g. something like `self.children = BacklinkingList(self)`. – 9000 Jun 18 '14 at 15:46

0 Answers0