2

我发现了奇怪的 Python 行为(或者我可能不明白继承和/或属性的默认值是如何工作的)。

对于给定的代码

class A(object):
    def __init__(self, s):
        self.s = s
        print "in init", self.s

class B(A):
    def __init__(self, s = set()):
        super(B, self).__init__(s)
        print "after super", self.s
        self.s.add('foo')
        print '--------------'

if __name__ == "__main__":
    a = B()
    b = B()

我得到以下输出:

in init set([])
after super set([])
--------------
in init set(['foo']) # Why it has value set in other object?!
after super set(['foo'])
--------------

当然,期望的行为是使用空集在第二个对象 (b) 中初始化 self.s,但由于未知原因,它从前一个对象获取状态。为什么会这样?如何获得期望的行为?

谢谢!

4

2 回答 2

8

您已成为可变默认参数陷阱的牺牲品。set()您在 B 中指定为默认值的是__init__将传递给B您创建的每个新对象的相同对象。将其放入self不会创建新副本,它只会创建对同一对象的引用。

您可能想在每个新对象中创建一个副本,因此请明确执行:

class A(object):
    def __init__(self, s):
        self.s = copy.copy(s)
于 2013-03-11T16:22:17.137 回答
0

当您为参数设置默认值时,该值是在您定义函数时计算的,而不是在您调用它时计算的。因此,它使用的set()是您定义类时创建的相同内容,并向其中添加越来越多的项目。

相反,典型的 Python 模式是使用None默认值,然后set()__init__.

class B(A):
  def __init__(self, s=None):
    if s is None:
      s = set()
于 2013-03-11T16:33:00.483 回答