In Python, why does .append give different results than using +?

Question:

I want to implement a very simple tree data structure in Python.
I want to make it so that everytime I add a new node and I specify its parent, then it is automatically added to the children attribute of its parent.

I have two different ways to do it, one works and one doesn’t but I don’t understand why.

class Node():
    def __init__(self, value, parent = None, children = []):
        self.value = value          #This is for us to see the name
        self.parent = parent        #Parent node
        self.children = children    #List of child nodes

        #Set this Node as a children of its own parent
        if not parent == None:
            #self.parent.children.append(self)  <--- wrong code
            self.parent.children = self.parent.children + [self]

    def __repr__(self):
        return str(self.value)

tree    = Node("tree")
branch1 = Node("branch1", parent = tree)
branch2 = Node("branch2", parent = tree)
leaf    = Node("leaf", parent = branch1)

Here is what I get with the code as is and what I would get if I replace the last line of __init__ with the commentated line.

print(tree.children)
#[branch1, branch2]        <--- expected
#[branch1, branch2, leaf]  <--- with wrong code

print(branch1.children)
#[leaf]                    <--- expected
#[branch1, branch2, leaf]  <--- with wrong code

Using the .append method adds the node not only to the list children of its parent but to everybody. Even if I define a new Node("other") completely detached from the others. Why is that?

Asked By: MannyC

||

Answers:

The problem is in the use of mutable default value:

def __init__(self, value, parent = None, children = []):

The empty list [] gets created only once, when the function is defined, and all invocations share the same list! This is why append to one list of children modifies all of them – because they all are one and the same list object. When you use + to append to the list, you work around the above bug because you re-create the list every time, thus unsharing the children objects.

The correct solution is to replace children=[] with something like:

def __init__(self, value, parent=None, children=None):
    if children is None:
        children = []

That will guarantee the creation of a new list for children, and then append and + should have the same result.

Answered By: user4815162342
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.