Question

I'm coding a TreeStructure (TS) class, which lets me create parent and child objects, which are linked to each other. Every TS -object has m_parent attribute, which is controlled with parent property, and also they have children list, which holds in all the children of this parent. Whenever I add a child to it's parent's children list, it gets added to it's own children list too? Here's what I have:

ROOT = "__ROOT__"

class TreeStructure:

    def __init__(self, parent=ROOT, children=[]):
        self.children = children
        self.parent = parent

    @property
    def parent(self):
        '''Returns m_parent'''
        if hasattr(self, "m_parent"):
            return self.m_parent
        else:
            return None

    @parent.setter
    def parent(self, parent=ROOT):
        '''Sets m_parent'''
        if type(parent) == type(self):
            if self.parent:
                del self.parent
            self.m_parent = parent
            self.m_parent.children.append(self)
        elif parent == ROOT:
            if self.parent:
                del self.parent
            self.m_parent = ROOT
        else:
            raise TypeError("Parent's type %s did not match objects type %s"
                            %(type(parent), type(self)))

    @parent.deleter
    def parent(self):
        '''Deletes m_parent'''
        if self.parent:
            if self.parent != ROOT:
                self.m_parent.children.remove(self)
            del self.m_parent

And now by creating two simple objects, it should work. However, it doesn't.

a = TreeStructure()
b = TreeStructure(a)

The problem appears at line 25, self.m_parent.children.append(self). If I add print's to both sides of that line, I see that both print(self.m_parent.children) and print(self.children) print an empty list [] BEFORE the append line. Now if I add the prints AFTER the append line, both prints will say [<__main__.TreeStructure object at 0x...>], which should only happen for the parent, not the child?

Was it helpful?

Solution

Do not use [] as a default value!

>>> def bad(default=[]):
...     default.append(1)
...     print default
... 
>>> bad()
[1]
>>> bad()
[1, 1]
>>> bad()
[1, 1, 1]
>>> def good(default=None):
...     if default is None:
...             default = []
...     default.append(1)
...     print default
... 
>>> good()
[1]
>>> good()
[1]

Default arguments are created when the function is defined, not when it is called. So only use non-mutable types for defaults. using integers, strings, tuples is okay, but if you want a default list or dictionary or anything mutable then use None and do the above trick.

Read this question and answers for better understanding of this matter.

OTHER TIPS

You've been caught out by old-style classes (which don't support descriptors, such as @propertys). You should be using:

class TreeStructure(object):

After doing that, your code works for me

EDIT:

I'm testing using python 2.7. In 3.x, all classes are new-style.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top