1

可能重复:
Python 中的“Least Astonishment”:可变默认参数
列表扩展了奇怪的行为
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]为什么会这样?

4

3 回答 3

5

b += [1]更改函数默认值(导致最不惊讶的常见问题解答)。b = b + [1]采用默认参数b- 使用 , 创建一个新列表+ [1]并将其绑定到b. 一个改变列表 - 另一个创建一个新列表。

于 2012-12-29T19:11:05.797 回答
5

在 Python 中,不能保证a += ba = a + b.

对于列表,就地someList += otherList修改,基本上等同于,然后将名称重新绑定到同一个列表。 另一方面,通过连接两个列表来构造一个列表,并将名称绑定到该新列表。someListsomeList.extend(otherList)someListsomeList = someList + otherListsomeList

这意味着,使用+=时,名称最终指向它已经指向的同一个对象,而使用 时+,它指向一个新对象。由于函数默认值只评估一次(参见这个被大量引用的问题),这意味着+=操作堆积起来,因为它们都修改了相同的原始对象(默认参数)。

于 2012-12-29T19:15:54.380 回答
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.

于 2012-12-29T19:27:52.963 回答