构造函数使用可选参数来做奇怪的事情 [英] Constructor does weird things with optional parameters

查看:71
本文介绍了构造函数使用可选参数来做奇怪的事情的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可能重复:
Python中的最小惊讶:可变的默认参数

Possible Duplicate:
least astonishment in python: the mutable default argument

我想了解python __init__构造函数的行为和含义.似乎有一个可选参数,当您尝试将现有对象设置为新对象时,现有对象的可选值将被保留并复制.

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.

看一个例子:

在下面的代码中,我试图创建一个带有节点和可能有许多子代的树形结构.在第一个类NodeBad中,构造函数具有两个参数:值和任何可能的子代.第二类NodeGood仅将节点的值作为参数.两者都有addchild方法来将子级添加到节点.

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.

使用NodeGood类创建树时,它会按预期工作.但是,当对NodeBad类执行相同的操作时,似乎只能将一次添加一个孩子!

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?

以下是示例:

#!/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

推荐答案

问题是,可选参数的默认值仅是一个实例.因此,例如,如果您说def __init__(self, value, c=[]):,则每次调用代码使用可选参数时,该列表[]都将传递到方法中.

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.

因此,基本上,仅应将诸如None之类的不可变日期类型用作可选参数的默认值.例如:

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 = []

这篇关于构造函数使用可选参数来做奇怪的事情的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆