函数执行后局部变量是否仍然存在?

时间:2015-02-13 01:11:26

标签: python-2.7

我很惊讶这个

>>> def f(arg=['local variable']):
...     arg.append('!')
...     print arg
...
>>> f()
['local variable', '!']
>>> f()
['local variable', '!', '!']
>>> f()
['local variable', '!', '!', '!']

我确定这是设计的,但是 WTF?!?我应该如何刷新本地命名空间,所以我对未来不感到惊讶?

[编辑]:

感谢解释,了解为何会发生这种情况。但在实际层面上,处理它的正确方法是什么?在处理它们之前,只需 deepcopy 所有默认变量,如下所示?

>>> from copy import deepcopy
>>> def f(arg=['local variable']):
...     arg = deepcopy(arg)
...     arg.append('!')
...     print arg
...
>>> f()
['local variable', '!']
>>> f()
['local variable', '!']
>>> f()
['local variable', '!']

1 个答案:

答案 0 :(得分:1)

局部变量不再存在。问题有点复杂。

def f(arg=['local variable'])

定义具有默认值的参数的方法。正如您应该知道的,Python不会复制对象,而是传递对它们的引用。这意味着为默认值创建了一些对象实例,如果未指定参数,则在参数中传递对它的引用(即,不复制实例)。如果对象是不可变的(例如字符串)但是列表是可变的,这通常非常直观。当你改变它时,你改变了用于默认值的实例,因此所有后续调用都会看到它。

如果你将函数看作一个类实例(它实际上是因为Python中的所有东西都是一个对象),你可以更好地想象它:

class _f:
    __arg = ['local variable']

    def __call__(self, arg = __arg):
        # The method body

f = _f()

现在您可以看到默认参数实例的实际生命周期与函数本身相同。

避免此问题的最佳方法是使用不可变对象而不是列表,使用元组,而不是类实例,使用None并在方法中构造实例:

def f(arg=('local variable',)):
    arg=list(arg)