将列表作为默认函数参数的奇怪行为

可能重复:
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 += ba = 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的不同值一起使用。

链接地址: http://www.djcxy.com/p/28575.html

上一篇: Strange behavior with a list as a default function argument

下一篇: Where to put default parameter value in C++?