将列表作为默认函数参数的奇怪行为
可能重复:
Python中的“最小惊讶”:可变的默认参数
列表扩展奇怪的行为
使用方法名称的金字塔遍历视图查找
假设我有这个功能:
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]
? 为什么会发生?
在Python中,不能保证a += b
和a = a + b
。
对于列表, someList += otherList
修改someList
,基本上等同于someList.extend(otherList)
,然后将名称someList
重新someList
到同一列表。 someList = someList + otherList
另一方面,通过连接两个列表构造一个新列表,并将名称someList
绑定到该新列表。
这意味着当+=
,名称指向它已经指向的同一个对象,而用+
指向一个新对象。 由于函数的默认值只能被计算一次(参见这个被大量引用的问题),这意味着+=
操作堆积如山,因为它们都修改了相同的原始对象(默认参数)。
b += [1]
改变了默认的功能(导致最少的惊讶FAQ)。 b = b + [1]
采用默认参数b
- 用+ [1]
创建一个新列表,并将其绑定到b
。 一个变更列表 - 另一个创建一个新的。
当你定义一个功能
>>> 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
更改为inplace,并且不会创建新列表。 而b
是保存在默认值元组中的列表。 因此,对列表所做的所有更改都会保存在该列表中,并且该函数的每次调用都会与b
的不同值一起使用。
上一篇: Strange behavior with a list as a default function argument