以下是三个python代码:
=======排名第1 =======
def foo(x, items=[]):
items.append(x)
return items
foo(1) #return [1]
foo(2) #return [1,2]
foo(3) #return [1,2,3]
======第2号========
def foo(x, items=None):
if items is None:
items = []
items.append(x)
return items
foo(1) #return [1]
foo(2) #return [2]
foo(3) #return [3]
======第3号=======
def foo(x, items=[]):
items.append(x)
return items
foo(1) # returns [1]
foo(2,[]) # returns [2]
foo(3) # returns [1,3]
对于代码No.1,由于未提供items
的值,我认为它应始终采用默认值[]。但参数items
的行为类似于静态变量,保留其值以供后续使用。 No.2的代码按我的预期执行:每次调用foo时,items
都会使用默认值None
。对于代码3,我完全不知道。为什么以上三段代码的执行方式如此不同?你可以解释吗?谢谢。
PS:我正在使用python 3.3.1
答案 0 :(得分:2)
"Least Astonishment" and the Mutable Default Argument
这个stackoverflow帖子给出了你的问题的答案,因为Python函数是具有状态的对象,“item”命名参数在多个调用之间保持状态。
它有其用途:
def calculate(a, b, c, memo={}):
try:
value = memo[a, b, c] # return already calculated value
except KeyError:
value = heavy_calculation(a, b, c)
memo[a, b, c] = value # update the memo dictionary
return value
所述
答案 1 :(得分:1)
源代码[]
不是值。它是一个评估列表的表达式。如果你评估一次,你会得到一个清单;如果你多次评估它,你会得到多个列表。要实现的关键是默认参数只评估一次默认表达式并存储它;因此,如果默认参数是一个列表,则每次调用时它总是相同的列表。
答案 2 :(得分:0)
似乎项目的默认列表对象的定义发生在函数定义时。如果您传入了某些内容,则items变量将使用您传入的对象,但否则默认为该默认列表对象。
因为示例1和3不重新定义默认列表对象(而示例2确实每次都将列表设置为空),所以对其进行的更改是累积的。在示例3中,传入一个单独的空列表对象以在items变量中使用意味着您对该函数的第二次执行对您定义的默认列表对象没有任何影响。