0

可能的重复:
Python 中的“Least Astonishment”:可变默认参数

使用 python 2.7 我遇到了奇怪的行为,我不确定如何解释它,或者它是否存在于任何 python 文档中。使用代码

class MyClass:
@staticmethod
def func(objects=[], a=None, b=None):
    objects.append(a)
    print 'objects: %s'%objects
    print 'b: %s'%b


MyClass.func(a='one')
MyClass.func(a='two', b='foo')
MyClass.func(a='three')

我得到了输出

objects: ['one']
b: None
objects: ['one', 'two']
b: foo
objects: ['one', 'two', 'three']
b: None

如您所见,该方法的第一个列表参数(对象)在调用中保留它的值。新值被附加到最后一个列表,即使在它的标头声明中它的默认值为 []。但是最后一个参数 (b) 不保留它的值,它在调用之间重置为默认值。

预期的(无论如何对我来说)是 objects 参数应该在任何调用方法时重置为默认值(就像 b 参数一样),但这似乎没有发生,似乎只发生在第一次调用时。

谁能解释这种行为?这是这个版本的python中的一个错误还是它的预期行为?可能与跨调用保留列表引用有关,但字符串变量 (b) 不是?我对这种行为感到非常困惑。

谢谢

4

2 回答 2

3

它与静态方法无关。这是 Python 中非常常见的错误。

Python 中的函数是一等对象,而不仅仅是代码块,因此您在参数中分配给对象的空列表是附加到函数对象的真实列表。每次调用它并将某些内容附加到该列表时,您都在使用相同的列表。很容易看到它以这种方式发生:

>>> def func(x, objects=[]):
...     objects.append(x)
... 
>>> func(1)
>>> func.func_defaults
([1],)
>>> func(2)
>>> func.func_defaults
([1, 2],)
>>> func(3)
>>> func.func_defaults
([1, 2, 3],)

func_defaults 是包含您设置的默认关键字参数的函数对象属性。看看列表是如何存在并改变的?

做你想做的事情的正确方法是:

class MyClass:
@staticmethod
def func(objects=None, a=None, b=None):
    if objects is None:
        objects = []
    objects.append(a)
    print 'objects: %s'%objects
    print 'b: %s'%b
于 2012-04-20T00:58:29.950 回答
1

这种行为是广为人知的,并且被许多人视为一种特性,并且不是特定于静态方法的。它适用于每个功能。当您将可变对象指定为参数的默认值时,就会发生这种情况

在 StackOverflow 上查看这个答案:默认参数陷阱 / 可变默认参数的危险

如果您了解可变性与不变性问题,请考虑以下函数/方法:

  • 定义时,分配默认参数值,
  • 当它被调用时,主体被执行,如果它就地更改可变的默认参数值,则更改后的值将用于每个后续调用,其中默认参数值没有通过提供不同的值而不是它来覆盖,
于 2012-04-20T01:03:29.663 回答