构造函数用可选参数做了奇怪的事情

发布于 2024-09-02 22:57:19 字数 1977 浏览 3 评论 0原文

可能的重复:
Python 中最不令人惊讶的地方:可变的默认参数

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

看一个例子:

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

当使用 NodeGood 类创建树时,它会按预期工作。然而,当使用 NodeBad 类做同样的事情时,似乎子项只能添加一次!

下面的代码将产生以下输出:

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

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
  print rootbad.children[0].value
  print rootbad.children[0].children[0].value
  print rootbad.children[0].children

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦屿孤独相伴 2024-09-09 22:57:19

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

因此基本上您应该只使用不可变的日期类型(例如 None)作为可选参数的默认值。例如:

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

然后您可以在方法主体中创建一个新列表:

if c == None:
  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.

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 = []
蝶…霜飞 2024-09-09 22:57:19

可变的默认参数是造成混乱的根源。

请参阅此答案:“最少惊讶”和可变默认参数

Mutable default arguments are a source of confusion.

See this answer: "Least Astonishment" and the Mutable Default Argument

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文