skip to Main Content
你的Python高效学习之道 025-5987-6503 contact@lessoncode.com

Python中的默认参数值

导致混淆的原因是当您使用“可变”对象作为默认值时,您会收到的行为; 也就是可以修改的值,如列表或字典。

例子:

>> def function(data=[]):
… data.append(1)
… return data

>>> function()
[1] >>> function()
[1, 1] >>> function()
[1, 1, 1]

您可以看到,列表会越来越长。 如果您查看列表标识,您将看到该函数保持返回相同的对象:

>> id(function())
12516768
>>> id(function())
12516768
>>> id(function())
12516768

原因很简单:在每次调用中,函数都使用相同的对象。 我们所做的修改是“粘性”。
为什么会发生这种情况?

始终评估默认参数值,当且仅当它们所属的“def”语句被执行时; 看到:

http://docs.python.org/ref/function.html(死链接)

还要注意,“def”是Python中的一个可执行语句,并且在“def”语句的环境中评估默认参数。 如果多次执行“def”,它将每次创建一个新的函数对象(新计算的默认值)。 下面我们来看一下例子。
该怎么办?

正如其他人所说,解决方法是使用占位符值而不是修改默认值。 没有一个共同的价值:

def myfunc(value=None):
if value is None:
value = [] # modify value here

如果需要处理任意对象(包括无),可以使用:

sentinel = object()

def myfunc(value=sentinel):
if value is sentinel:
value = expression
# use/modify value here

在旧的代码中,在“对象”之前写过,你有时会看到这样的东西

sentinel = [‘placeholder’]

用于创建具有唯一身份的非假对象; []每次评估时都会创建一个新列表。
可变默认值的有效用法

最后,应该注意的是,更高级的Python代码通常使用这种机制来获得优势; 例如,如果您在循环中创建一堆UI按钮,则可以尝试以下操作:

for i in range(10):
def callback():
print “clicked button”, i
UI.Button(“button %s” % i, callback)

只发现所有回调打印相同的值(在这种情况下最有可能是9)。 原因是Python的嵌套范围与变量绑定,而不是对象值,所以所有回调实例都将看到“i”变量的当前(= last)值。 要解决这个问题,请使用显式绑定:

for i in range(10):
def callback(i=i):
print “clicked button”, i
UI.Button(“button %s” % i, callback)

“i = i”部分将参数“i”(局部变量)绑定到外部变量“i”的当前值。

另外两个用途是本地缓存/记忆,例如:

def calculate(a, b, c, memo={}):
try:
value = memo[a, b, c] # return already calculated value
except KeyError:
value = heavy_calculation(a, b, c)
memo[a, b, c] = value # update the memo dictionary
return value

(这对于某些类型的递归算法特别好)

并且,对于高度优化的代码,全局名称的本地重新绑定:

import math

def this_one_must_be_fast(x, sin=math.sin, cos=math.cos):

这是如何工作的?

当Python执行“def”语句时,它需要一些现成的部分(包括函数体的编译代码和当前命名空间),并创建一个新的函数对象。 当它这样做时,它也会评估默认值。

各种组件可用作功能对象上的属性; 使用我们上面使用的功能:

>> function.func_name
‘function’
>>> function.func_code
", line 1>
>>> function.func_defaults
([1, 1, 1],)
>>> function.func_globals
{'function': ,
'__builtins__': <module '__builtin__' (built-in)>,
'__name__': '__main__', '__doc__': None}

由于您可以访问默认值,您还可以修改它们:

>>> function.func_defaults[0][:] = [] >>> function()
[1] >>> function.func_defaults
([1],)

但是,这不是我建议定期使用的东西…

重置默认值的另一种方法是简单地重新执行相同的“def”语句。 然后,Python将为代码对象创建一个新的绑定,评估默认值,并将函数对象分配给与之前相同的变量。 但是,再次,只有当你知道你在做什么时,才能做到这一点。

是的,如果你碰巧有件而不是功能,你可以使用新模块中的函数类创建自己的函数对象。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Back To Top