问题描述
任何人对Python进行足够长时间的修补都被以下问题咬伤(或弄成碎片):
Anyone tinkering with Python long enough has been bitten (or torn to pieces) by the following issue:
def foo(a=[]):
a.append(5)
return a
Python新手希望此函数始终返回仅包含一个元素的列表:[5]
.结果是非常不同的,并且非常令人惊讶(对于新手而言):
Python novices would expect this function to always return a list with only one element: [5]
. The result is instead very different, and very astonishing (for a novice):
>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()
我的一位经理曾经第一次遇到此功能,并将其称为严重的设计缺陷".我回答说,这种行为有一个基本的解释,如果您不了解内部原理,那确实是非常令人困惑和出乎意料的.但是,我无法(对自己)回答以下问题:在函数定义而不是函数执行时绑定默认参数的原因是什么?我怀疑经验丰富的行为是否具有实际用途(谁真正在C中使用了静态变量,却没有滋生bug?)
A manager of mine once had his first encounter with this feature, and called it "a dramatic design flaw" of the language. I replied that the behavior had an underlying explanation, and it is indeed very puzzling and unexpected if you don't understand the internals. However, I was not able to answer (to myself) the following question: what is the reason for binding the default argument at function definition, and not at function execution? I doubt the experienced behavior has a practical use (who really used static variables in C, without breeding bugs?)
修改:
Baczek举了一个有趣的例子.连同您的大多数评论,特别是Utaal的评论,我进一步阐述了:
Baczek made an interesting example. Together with most of your comments and Utaal's in particular, I elaborated further:
>>> def a():
... print("a executed")
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print(x)
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
在我看来,设计决策似乎与将参数范围放在哪里有关:在函数内部还是一起"使用?
To me, it seems that the design decision was relative to where to put the scope of parameters: inside the function or "together" with it?
在函数内部进行绑定将意味着x
在调用该函数(未定义)时有效地绑定到了指定的默认值,这会带来严重的缺陷:def
行在其中是"hybrid"感觉(功能对象的)绑定的一部分将在定义时发生,而部分(默认参数的分配)将在函数调用时发生.
Doing the binding inside the function would mean that x
is effectively bound to the specified default when the function is called, not defined, something that would present a deep flaw: the def
line would be "hybrid" in the sense that part of the binding (of the function object) would happen at definition, and part (assignment of default parameters) at function invocation time.
实际行为更加一致:执行该行时,将评估该行的所有内容,这意味着在函数定义时进行.
The actual behavior is more consistent: everything of that line gets evaluated when that line is executed, meaning at function definition.
推荐答案
实际上,这不是设计缺陷,也不是由于内部因素或性能所致.
这完全是因为Python中的函数是一流的对象,而不仅仅是一段代码.
Actually, this is not a design flaw, and it is not because of internals, or performance.
It comes simply from the fact that functions in Python are first-class objects, and not only a piece of code.
一旦您开始思考这种方式,那便完全有意义:一个函数是根据其定义求值的对象;默认参数是一种成员数据",因此它们的状态可能会从一个调用更改为另一个调用-完全与其他任何对象一样.
As soon as you get to think into this way, then it completely makes sense: a function is an object being evaluated on its definition; default parameters are kind of "member data" and therefore their state may change from one call to the other - exactly as in any other object.
无论如何,Effbot在默认参数值中都很好地解释了这种行为的原因.在Python中.
我发现它很清楚,我真的建议您阅读它,以更好地了解函数对象的工作原理.
In any case, Effbot has a very nice explanation of the reasons for this behavior in Default Parameter Values in Python.
I found it very clear, and I really suggest reading it for a better knowledge of how function objects work.
这篇关于“最少惊讶"指的是:和可变默认参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!