"最小惊讶"和可变的默认参数
任何长时间使用Python的人都会被以下问题困扰(或者被撕裂):
def foo(a=[]):
a.append(5)
return a
Python新手会期望这个没有参数的函数总是返回一个只有一个元素的列表:[5]
。结果却大相径庭,非常令人惊讶(对于一个新手来说):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
我的一位经理第一次遇到这个问题,称其为语言的“设计缺陷”。我回答说这种行为有一个基本的解释,如果你不了解内部原理,确实会感到困惑和意外。然而,我无法回答(给自己)以下问题:为什么在函数定义时绑定默认参数,而不是在函数执行时?我怀疑这种经验行为在实际应用中没有实际用途(谁真的在C语言中使用了静态变量,而不产生错误?)
编辑:
Baczek提出了一个有趣的例子。结合你的大部分评论,特别是Utaal的评论,我进一步阐述了:
def a():
print("a executed")
return []
def b(x=a()):
x.append(5)
print(x)
a executed
>>> b()
[5]
>>> b()
[5, 5]
对我来说,这个设计决策似乎与参数的作用域有关:是在函数内部还是与它“一起”?
在函数内部进行绑定意味着在函数调用时,x
实际上会被绑定到指定的默认值,而不是在定义时。这似乎是一个深刻的缺陷:def
行在某种程度上是“混合”的,因为在定义行执行时,函数对象的绑定(以及默认参数的赋值)会发生。
实际的行为更加一致:在定义行执行时,该行的所有内容都会被计算。
实际上,这不是设计缺陷,也不是因为内部或性能问题。这只是因为 Python 中的函数是一等对象,不仅仅是一段代码。
当你这样想时,就完全明白了:函数是在定义时被求值的对象;默认参数是“成员数据”,因此它们的状态可能会在一次调用到另一次调用之间发生变化——就像在任何其他对象中一样。
无论如何,effbot(Fredrik Lundh)对这种行为的原因有很好的解释,可以参考他在Python中的默认参数值中的文章。
我觉得很清楚,我非常建议阅读它,以便更好地了解函数对象的工作原理。
标签:函数,Python,惊讶,默认,参数,可变,foo,def From: https://www.cnblogs.com/xiaomandujia/p/17794493.html