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

时间:2012-12-29 19:07:00

标签: python list default-arguments

  

可能重复:
  “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]的区别如何?为什么会这样?

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:5)

在Python中,无法保证a += ba = 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的不同值。