重要警告:默认值仅评估一次 ... 如果您不想要默认值 在后续电话之间共享,你 可以写这样的功能 代替:
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是否指向在堆或堆栈中创建的空列表?
答案 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对象而不是空列表对象。