Constructor does weird things with optional parameters [duplicate]
Possible Duplicate:
least astonishment in python: the mutable default argument
I want to understand of the behavior and implications of the python __init__
constructor. It seems like when there is an optional parameter and you try and set an existing object to a new object the optional value of the existing object is preserved and copied.
Look at an example:
In the code below I am trying to make a tree structure with nodes and possibly many children . In the first class NodeBad
, the constructor has two parameters, the value and any possible children. The second class NodeGood
only takes the value of the node as a parameter. Both have an addchild
method to add a child to a node.
When creating a tree with the NodeGood
class, it works as expected. However, when doing the same thing with the NodeBad
class, it seems as though a child can only be added once!
The code below will result in the following output:
Good Tree
1
2
3
[< 3 >]
Bad Tree
1
2
2
[< 2 >, < 3 >]
Que Pasa?
Here is the 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
p开发者_如何学编程rint rootbad.children[0].value
print rootbad.children[0].children[0].value
print rootbad.children[0].children
The problem is, the default value of an optional argument is only a single instance. So for example, if you say def __init__(self, value, c=[]):
, that same list []
will be passed into the method each time an optional argument is used by calling code.
So 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 method body:
if c == None:
c = []
Mutable default arguments are a source of confusion.
See this answer: "Least Astonishment" and the Mutable Default Argument
精彩评论