dict.update是否会影响函数的argspec?
import inspect
class Test:
def test(self, p, d={}):
d.update(p)
return d
print inspect.getargspec(getattr(Test, 'test'))[3]
print Test().test({'1':True})
print inspect.getargspec(getattr(Test, 'test'))[3]
我期望argspec for Test.test不会改变,但由于dict.update它会。为什么?dict.update是否会影响函数的argspec?
由于字典是可变对象。当您拨打d.update(p)
时,您实际上正在突变字典的默认实例。这是一个常见的问题;特别是,你应该从来没有使用可变对象作为参数列表中的默认值。
一个更好的办法来做到这一点如下:
class Test:
def test(self, p, d = None):
if d is None:
d = {}
d.update(p)
return d
Python中的默认参数是定义函数时设置到任何对象,即使你设置了可变对象。这个问题应该解释为什么Python是SO问题least astonishment in python: the mutable default argument。
基本上,每次调用该函数时使用相同的默认对象,而不是每次都创建一个新副本。例如:
>>> def f(xs=[]):
... xs.append(5)
... print xs
...
>>> f()
[5]
>>> f()
[5, 5]
解决这个问题的最简单的方法就是让你的实际默认参数None
,然后简单地检查None
和提供功能的默认,例如:
>>> def f(xs=None):
... if xs is None:
... xs = []
... xs.append(5)
... print xs
...
>>> f()
[5]
>>> f()
[5]
请注意,“Python中的默认参数是可变的。”并不完全正确。默认参数可以是可变的(当它们是可变对象时,如列表)和不可变的(当它们是不可变的,如int)。有些重要的部分是只有一个对象被设置为默认参数。 – 2010-04-28 17:10:49
@Mike:好点,我编辑了我的答案,以改善该陈述的措词。 – 2010-04-28 17:23:50
'd = d或{}'有点奇怪,因为如果有人通过你自己的* dict对象传入其中的东西来改变它,但是如果有人传入了*他们自己的* dict对象(或另一种类似于它的对象)那是空的,它使用一个新的dict对象。如果我正在编写这样的代码,那么我可能会使用'if d是None:d = {}'或者更可能的是,绝不会改变我接收的参数。 – 2010-04-28 17:01:28
你在这里得到了一点 - 我正在编辑我的解决方案,以适应这一点。无论如何,我也同意不应该改变那里收到的论点。 – 2010-04-28 18:37:22