不可变动的默认值(Unmutable defaults)
-
在官方的邮件列表中看到以下这个话题:
[quote]Dear community,
It seems we have all made a quite common mistake in our python code - using empty lists or dictionaries as default values for functions.
As it turns out, we should not have done that because that makes the defaults mutable, which may provoke strange bugs, very hard to reproduce.
So please allow me to ask you all to change the code you contributed to the "community" and/or "extra-addons" branches. For example we should now change this
def foo(...., context={},....):
....
to this :
def foo(...., context=None,....):
# you should add this test only if the context is actually used
if context is None:
context={}
....I humbly suggest you fix the trunk branch in priority, and fix the 5.0 branches only if you feel totally comfortable with the changes.
Please read https://bugs.launchpad.net/openobject-server/+bug/525808 for more detail.Lionel, for Numérigraphe SARL[/quote]
他的大意是说在OE的开发中大量存在着一种对有默认值的参数的误用,如果不加以规范的话,会导致很多不可预测的错误,它建议将:[code]def foo(..., context={},...):
...
[/code]转换为:[code]def foo(..., context=None, ...):
if context = None:
context = {}
...[/code]可是为什么这么麻烦从第一种看起来很简单的形式转变到这第二种颇啰嗦的形式呢,第一种形式会带来什么问题呢?在Python的函数定义中有两种形式的参数,一种是普通的形参,另一种是带默认值的形参。对于第一种形参,调用函数时必须提供对应的实参,而对于第二种形参,调用函数时如果没有提供对应的实参则会使用函数定义中该形参的默认值。所以第二种参数也称为[b]可选参数[/b]。
这里需要强调的是,可选参数的默认值是在函数定义阶段计算确认的。函数调用时若没有提供相应的实参就会对这个默认值对象进行操作,当这个默认值是一个[b]可变对象[/b](mutable object)的话,事情就会变得有些微妙:[code]def f(x, y=[]):
y.append(x)
return yprint f(10) #显示 [10]
print f(11) #显示 [10, 11][/code]我们这里定义了一个简单的函数f,其中y是其一个可选参数,其默认值对应一个空的列表(列表作为一个容器是可变对象)。当我们用f(10)调用f函数时得到了[10]这个结果,当我们再次调用f函数f(11)时,记得我们还是在使用y所对应的这个列表对象而其成员对象已经包括了第一次运算的结果10了,所以第二次调用的结果就会是[10,11]。这往往并不是我们所期望的,也是带来不可预测问题的根源,所以我们将代码改成:[code]def f(x, y=None):
if y is None: y = []
y.append(x)
return y
print y(10) #显示 [10]
print y(11) #显示 [11][/code]朋友们在代码开发时,请注意这方面的问题。[[i] 本帖最后由 digitalsatori 于 2010-3-14 23:05 编辑 [/i]]