禁止共享默认arg b / w连续调用

时间:2011-07-04 04:39:11

标签: python

Python Tutorial -

  

重要警告:默认值仅评估一次   ...   如果您不想要默认值   在后续电话之间共享,你   可以写这样的功能   代替:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

我仍然在期待:

print f(1)    # [1]
print f(2)    # [1,2]
print f(3)    # [1,2,3]

我的理由:

L=None执行了默认值(f(1)),这有助于L指向fn正文中的新空列表。但是,在连续调用中,L=None未执行;所以L仍然指向现在已经有1的列表,后续调用只是向它添加更多元素,从而共享L

我在哪里思考错误?


更新

def f(a, L=[]):
    L.append(a)
    return L

这里的L是否指向在堆或堆栈中创建的空列表?

3 个答案:

答案 0 :(得分:2)

L是参数的名称,但也是一个局部变量。重新绑定它会重新绑定局部变量,但不会更改默认参数。

更新编辑:

Python没有“堆”和“堆栈”的方式与C相同;所有它都是对象,以及对这些对象的引用。您的函数调用返回对作为L函数的f参数的默认值创建的相同列表的引用,并且任何改变它的操作都将改变默认参数的值。 / p>

答案 1 :(得分:0)

The default value is evaluated only once

表示如果你def foo(a, b=len([1,2,3])) b将被设置为3,如果你调用foo,它将不会对len进行任何函数调用。

=运算符将对象分配给名称。它不会改变先前的对象。

答案 2 :(得分:0)

如果您运行以下功能,它将帮助您了解它的工作原理。

def f(a, L=[]):
    print("id default: ", id(L))
    L.append(a)
    print("id used: ", id(L)
    return L

注意1对象地址,我们只使用默认列表对象,我们正在更改它。

def f(a, L=[]):
    print("id default: ", id(L))
    if L == []:
        L = []
    L.append(a)
    print("id used: ", id(L))      
    return L 

注意2个不同的对象地址,当您在函数中再次指定L = []时,您使用的是不同的列表对象而不是默认列表对象,这就是默认列表对象不会更改的原因。

def f(a, L=None):
    print("id default", id(L))
    if L is None:
        L = []
    L.append(a) 
    print("id used: ", id(L))      
    return L 

此函数与上面的函数基本相同,相同的想法,但它使用None对象而不是空列表对象。