Python constructor does weird things with extra parameters

Possible duplicate:
least surprise in python: mutable default argument

I want to understand the behavior and consequences of the python __init__ constructor. It seems that when there is an optional parameter, and you are trying to install an existing object on a new object, the additional value of the existing object is saved and copied.

See an example:

In the code below, I'm trying to create a tree structure with nodes and possibly with a lot of children. In the first NodeBad class NodeBad constructor has two parameters: a value and any possible children. The second NodeGood class takes a node value as a parameter. Both have an addchild method to add a child to a node.

When creating a tree with the NodeGood class NodeGood it works as expected. However, doing the same with the NodeBad class, it seems that a child can only be added once!

The code below will lead to the following output:

 Good Tree 1 2 3 [< 3 >] Bad Tree 1 2 2 [< 2 >, < 3 >] 

Que Pasa?

Here is an example:

 #!/usr/bin/python class NodeBad: def __init__(self, value, c=[]): self.value = value self.children = c def addchild(self, node): self.children.append(node) def __str__(self): return '< %s >' % self.value def __repr__(self): return '< %s >' % self.value class NodeGood: def __init__(self, value): self.value = value self.children = [] def addchild(self, node): self.children.append(node) def __str__(self): return '< %s >' % self.value def __repr__(self): return '< %s >' % self.value if __name__ == '__main__': print 'Good Tree' ng = NodeGood(1) # Root Node rootgood = ng ng.addchild(NodeGood(2)) # 1nd Child ng = ng.children[0] ng.addchild(NodeGood(3)) # 2nd Child print rootgood.value print rootgood.children[0].value print rootgood.children[0].children[0].value print rootgood.children[0].children print 'Bad Tree' nb = NodeBad(1) # Root Node rootbad = nb nb.addchild(NodeBad(2)) # 1st Child nb = nb.children[0] nb.addchild(NodeBad(3)) # 2nd Child print rootbad.value print rootbad.children[0].value print rootbad.children[0].children[0].value print rootbad.children[0].children 
+6
python constructor optional-parameters
source share
2 answers

The problem is that the default value of an optional argument is only one instance. So, for example, if you say def __init__(self, value, c=[]): the same list [] will be passed to the method every time additional code is used when calling the code.

Basically, you should only use immutable date types, such as None for the default value of an optional argument. For example:

 def __init__(self, value, c=None): 

Then you could just create a new list in the body of the method:

 if c == None: c = [] 
+12
source share

Default variable arguments are a source of confusion.

Take a look at this answer: Least Surprise and Mutable Default Argument

+2
source share

All Articles