2010-04-28 65 views
4
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?

回答

5

由于字典是可变对象。当您拨打d.update(p)时,您实际上正在突变字典的默认实例。这是一个常见的问题;特别是,你应该从来没有使用可变对象作为参数列表中的默认值。

一个更好的办法来做到这一点如下:

class Test: 
    def test(self, p, d = None): 
     if d is None: 
      d = {} 
     d.update(p) 
     return d 
+1

'd = d或{}'有点奇怪,因为如果有人通过你自己的* dict对象传入其中的东西来改变它,但是如果有人传入了*他们自己的* dict对象(或另一种类似于它的对象)那是空的,它使用一个新的dict对象。如果我正在编写这样的代码,那么我可能会使用'if d是None:d = {}'或者更可能的是,绝不会改变我接收的参数。 – 2010-04-28 17:01:28

+0

你在这里得到了一点 - 我正在编辑我的解决方案,以适应这一点。无论如何,我也同意不应该改变那里收到的论点。 – 2010-04-28 18:37:22

2

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] 
+1

请注意,“Python中的默认参数是可变的。”并不完全正确。默认参数可以是可变的(当它们是可变对象时,如列表)和不可变的(当它们是不可变的,如int)。有些重要的部分是只有一个对象被设置为默认参数。 – 2010-04-28 17:10:49

+0

@Mike:好点,我编辑了我的答案,以改善该陈述的措词。 – 2010-04-28 17:23:50

相关问题