有关使用默认参数值的python名称的问题

时间:2010-08-12 05:40:31

标签: python variables

我今天正在读这篇文章: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仍然绑定到它。但话说回来,我想知道我是如何获得相同的默认值而不是新的[]。有人可以为我理顺吗?

谢谢!

1 个答案:

答案 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}}并检查它。