2

I'm trying to do a simple tree, with name for each child.

Here is a minimal code :

class Node:
   def __init__(self, msg, childs={}):
       self.msg = msg
       self.childs=childs

tree = Node('1')
tree.childs['2'] = Node('2')
tree.childs['3'] = Node('3')

Executing print(tree.childs) give me an expected output :

{'3': <main.Page object at 0x7f1fda9f77b8>, '2': <main.Page object at 0x7f1fda9f77f0>}

But executing print(tree.childs['2'].childs) give me :

{'3': <main.Page object at 0x7f1fda9f77b8>, '2': <main.Page object at 0x7f1fda9f77f0>}

Where the expected output would be :

{}

Where am I wrong ? Why am I wrong ?

Astariul
  • 2,190
  • 4
  • 24
  • 41

2 Answers2

4

The typical issue with a mutable default argument. Do instead:

class Node:
    def __init__(self, msg, childs=None):
        self.msg = msg
        self.childs = childs or {}
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • Oh I see. I know it was something about mutable, but couldn't understand where the problem was. So what is happening is when I change the childs of the first node, since every node refer to the same default argument and I just changed it, then they all refer to this... – Astariul Oct 25 '18 at 06:42
  • 1
    @Astariul `Node('1')` copies the default argument to its own instance attribute `childs` and subsequently mutates it: `tree.childs['2'] = Node('2')`. This will affect the default argument which was bound at function definition time. All other nodes using the default argument will now have node2 in theri childs. – user2390182 Oct 25 '18 at 06:46
3

You should not make a mutable object such as {} as the default value for your __init__ method, since its reference gets reused for the subsequent calls and any changes to the mutable object would be reflected on any other variables holding the same reference.

Change your __init__ method to:

class Node:
   def __init__(self, msg, childs=None):
       self.msg = msg
       self.childs=childs or {}
blhsing
  • 91,368
  • 6
  • 71
  • 106
  • You should be on SO long enough to know that it's inevitable that some of us will end up with the same code when the answer is this obvious. You wrote a much shorter explanation, which is why you posted before I did. – blhsing Oct 25 '18 at 06:42
  • Sorry i accepted the first answer first, but I appreciate the explanation. – Astariul Oct 25 '18 at 06:43
  • @schwobaseggl BTW I never copy anyone's code. That was totally uncalled for and I do feel offended. And if you look closely I don't actually have the same code as yours. You put extra spaces in the OP's original code (before and after `=`) and I did not. – blhsing Oct 25 '18 at 06:47
  • @schwobasegg I do delete my post too when I find my answer to be a duplicate once I post, although in this particular case I decided to keep my post just for the extra words I wrote. +1'd for you though. – blhsing Oct 25 '18 at 06:51