Strange behavior with a list as a default function argument

Possible Duplicate:
“Least Astonishment” in Python: The Mutable Default Argument
List extending strange behaviour
Pyramid traversal view lookup using method names

Let's say I have this function:

def a(b=[]):
    b += [1]
    print b

Calling it yields this result:

>>> a()
[1]
>>> a()
[1, 1]
>>> a()
[1, 1, 1]

When I change b += [1] to b = b + [1] , the behavior of the function changes:

>>> a()
[1]
>>> a()
[1]
>>> a()
[1]

How does b = b + [1] differ from b += [1] ? Why does this happen?


In Python there is no guarantee that a += b does the same thing as a = a + b .

For lists, someList += otherList modifies someList in place, basically equivalent to someList.extend(otherList) , and then rebinds the name someList to that same list. someList = someList + otherList , on the other hand, constructs a new list by concatenating the two lists, and binds the name someList to that new list.

This means that, with += , the name winds up pointing to the same object it already was pointing to, while with + , it points to a new object. Since function defaults are only evaluated once (see this much-cited question), this means that with += the operations pile up because they all modify the same original object (the default argument).


b += [1] alters the function default (leading to the least astonishment FAQ). b = b + [1] takes the default argument b - creates a new list with the + [1] , and binds that to b . One mutates the list - the other creates a new one.


When you define a function

>>> def a(b=[]):
    b += [1]
    return b

it saves all the default arguments in a special place. It can be actually accessed by:

>>> a.func_defaults
([],)

The first default value is a list has the ID:

>>> id(a.func_defaults[0])
15182184

Let's try to invoke the function:

>>> print a()
[1]
>>> print a()
[1, 1]

and see the ID of the value returned:

>>> print id(a())
15182184
>>> print id(a())
15182184

As you may see, it's the same as the ID of the list of the first default value.

The different output of the function is explained by the fact that b+=... modifies the b inplace and doesn't create a new list. And b is the list being kept in the tuple of default values. So all your changes to the list are saved there, and each invocation of the function works with the different value of b .

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

上一篇: Python中闭包的可变默认参数的实例化时间

下一篇: 将列表作为默认函数参数的奇怪行为