可能重复:
“Least Astonishment” in Python: The Mutable Default Argument
List extending strange behaviour
Pyramid traversal view lookup using method names
假设我有这个功能:
def a(b=[]):
b += [1]
print b
调用它会产生以下结果:
>>> a()
[1]
>>> a()
[1, 1]
>>> a()
[1, 1, 1]
当我将b += [1]
更改为b = b + [1]
时,该功能的行为会发生变化:
>>> a()
[1]
>>> a()
[1]
>>> a()
[1]
b = b + [1]
与b += [1]
的区别如何?为什么会这样?
答案 0 :(得分:5)
b += [1]
改变了函数默认值(导致最不惊讶的常见问题解答)。 b = b + [1]
采用默认参数b
- 使用+ [1]
创建新列表,并将其绑定到b
。一个变异列表 - 另一个创建一个新列表。
答案 1 :(得分:5)
在Python中,无法保证a += b
与a = a + b
做同样的事情。
对于列表,someList += otherList
修改了someList
,基本上等同于someList.extend(otherList)
,然后将名称someList
重新绑定到同一列表。另一方面,someList = someList + otherList
通过连接两个列表构建 new 列表,并将名称someList
绑定到该新列表。
这意味着,对于+=
,名称会指向它已指向的同一对象,而使用+
时,它指向一个新对象。由于函数默认值只被评估一次(参见this much-cited question),这意味着对于+=
,操作会堆积起来,因为它们都修改了相同的原始对象(默认参数)。
答案 2 :(得分:0)
定义函数时
>>> def a(b=[]):
b += [1]
return b
它将所有默认参数保存在特殊位置。它实际上可以通过以下方式访问:
>>> a.func_defaults
([],)
第一个默认值是list
,其ID为:
>>> id(a.func_defaults[0])
15182184
让我们尝试调用函数:
>>> print a()
[1]
>>> print a()
[1, 1]
并查看返回值的ID:
>>> print id(a())
15182184
>>> print id(a())
15182184
如您所见,它与第一个默认值列表的ID相同。
函数的不同输出是由b+=...
修改b
到位并且不创建新列表的事实解释的。 b
是保存在默认值元组中的列表。因此,对列表的所有更改都保存在那里,并且函数的每次调用都使用b
的不同值。