我今天正在读这篇文章:http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#default-parameter-values而我似乎无法理解幕后发生的事情。
def bad_append(new_item, a_list=[]):
a_list.append(new_item)
return a_list
这里的问题是默认值 a_list的值,一个空列表,是 在功能定义时评估 。 所以每次调用这个函数, 你得到相同的默认值。试试吧 好几次:
我想首先,什么时候是功能定义阶段?它是在实际主函数执行之前的初始化阶段吗?
我最初的想法是,在函数运行后立即丢弃名称a_list,因此无论[]
突变为什么都将被垃圾收集。现在,我认为a_list根本不会被丢弃,因为它只是绑定到对象[]
的名称所以它永远不会被垃圾收集,因为a_list仍然绑定到它。但话说回来,我想知道我是如何获得相同的默认值而不是新的[]
。有人可以为我理顺吗?
谢谢!
答案 0 :(得分:2)
什么时候是功能定义阶段?
在Python参考中查看"Function definitions":
执行函数定义时会计算默认参数值。这意味着在定义函数时,表达式将被计算一次,并且相同的“预先计算”值将用于每次通话。这对于理解默认参数何时是可变对象(例如列表或字典)尤其重要:如果函数修改对象(例如,通过将项附加到列表),则默认值实际上被修改。这通常不是预期的。解决这个问题的方法是使用
None
作为默认值,并在函数体中明确地测试它,例如:def whats_on_the_telly(penguin=None): if penguin is None: penguin = [] penguin.append("property of the zoo") return penguin
执行函数定义时,评估参数。如果它在模块中,则在导入模块时会发生。如果它在一个类中,那就是类定义运行的时候。如果它在函数中,则在函数执行时发生。请记住,Python模块是从上到下进行评估的,并不像某些语言那样自动拥有明确的“主要功能”。
例如,如果将函数定义放在函数中,则每次都会得到函数的新副本:
>>> def make_function():
... def f(value=[]):
... value.append('hello')
... return value
... return f
...
>>> f1 = make_function()
>>> f2 = make_function()
>>> f1()
['hello']
>>> f1()
['hello', 'hello']
>>> f2()
['hello']
函数定义创建一个新的function
对象,为其分配各种属性,包括代码,形式参数和默认值,并将其存储在作用域中的名称中。通常,对于任何给定的函数,这只发生一次,但有时可以再次执行函数的定义。
我最初的想法是在函数运行后立即丢弃名称a_list,因此无论
[]
突变为什么都将被垃圾收集。
在函数体内,代码可以使用名称a_list
。因此,名称及其指向的值必须仍然可用。它存储在函数的func_defaults
属性中。
但话又说回来,我想知道我是如何得到相同的默认值而不是新的[]。
因为仅在定义函数时评估[]
,而不是在调用函数时评估a_list
,并且即使在重复调用中,名称None
也指向同一对象。同样,如果您想要替代行为,请使用不可变的内容,例如{{1}}并检查它。