【问题标题】:Constructor does weird things with optional parameters [duplicate]构造函数用可选参数做奇怪的事情[重复]
【发布时间】:2011-02-23 09:16:27
【问题描述】:

可能重复:
least astonishment in python: the mutable default argument

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

看一个例子:

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

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

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

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

魁帕萨?

示例如下:

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

【问题讨论】:

标签: python constructor optional-parameters


【解决方案1】:

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

所以基本上你应该只使用不可变的日期类型,例如None 作为可选参数的默认值。例如:

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

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

if c == None:
  c = []

【讨论】:

  • 只有在使用 mutable 数据类型作为默认参数时才会出现问题。任何不可变类型(整数、字符串、元组等)都没有问题(我不会将其命名为常量值)。
  • 好点,我刚刚更新了我的答案。谢谢!
  • 值得澄清的是,这不是特定于 __init__ 的,也不是特定于类的,而是适用于任何函数。
【解决方案2】:

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

看到这个答案:"Least Astonishment" and the Mutable Default Argument

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-24
    • 1970-01-01
    • 2013-05-05
    • 1970-01-01
    • 1970-01-01
    • 2013-05-10
    • 1970-01-01
    相关资源
    最近更新 更多