2010-04-28 126 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

相關問題