我理解不应该在Python中使用mutable default parameter value(有一些例外),因为这个值在定义函数时只被评估和存储一次,而不是每次稍后调用该函数。
我对此的理解是这样的(使用下面的例子;请原谅我不精确的语言,因为我只是Python编程的初学者,因为这个而被困在我教科书的功能章节中):
def f(x = [1, 2, 3]):
x.append(4)
print(x)
f()
f()
1)定义函数f,x(f中的局部变量)假设默认变量为[1,2,3](甚至在调用函数之前)
2)当调用f()时,由于没有传递参数,x仍然是[1,2,3],并且x继续具有其默认值
3)x用append修改,变成[1,2,3,4],并按原样打印
然而,这是我的困惑所在。我假设:
4)当f结束时,x被破坏(在堆栈中或你称之为的任何东西)并且不再与列表对象[1,2,3,4]相关联**
5)回收列表对象[1,2,3,4],因为不再有引用它的变量
因此,
6)当第二次调用f()时,我希望Python输出一个错误,因为x现在不再有与之关联的值了。换句话说,当Python被回收/销毁时,Python如何重用上一次评估的默认值?
感谢您的所有帮助和解释!
**我从Ned Batchelder's page on variable name assignment得到的这种理解(见下文)
答案 0 :(得分:7)
虽然你可能觉得在执行结束时x,默认值被处理掉,但事实并非如此。
事实上,Python有一个全局命名空间,其中包含所有可供您使用的名称(您导入或定义的内置函数,类和函数)。
此命名空间的内容由对象组成。功能也是对象。
作为测试,如果你在脚本或python命令行中尝试这个,你会看到我的意思:
def f(x = [1, 2, 3]):
x.append(4)
print(x)
print dir(f)
你会看到函数f的对象性质。作为对象,默认值在属性f.func_defaults
中引用,因此它们始终可用,如果可变,它们会保留更改,为您提供可能不需要的副作用。
编辑:在python 3中,该属性已被f.__defaults__
答案 1 :(得分:3)
在您的情况下,列表有两个引用,一个是在函数的后台存储,作为参数x
的默认值。
在没有x
的情况下调用函数时,会创建对相同列表的新引用作为局部变量x
。然后通过第二个引用附加到列表。并且在调用之后,第二个引用被垃圾收集。第一个引用仍然指向同一个列表,现在有一个元素。
或者简而言之:一直只有一个列表。