2009-09-02 76 views
5

我發現,在新的樣式類的子類和字典更新一個奇怪的問題:Python方法:默認的參數值計算一次

Python 2.6.2 (r262:71605, Apr 14 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] on 
win32 
>>> class a(object): 
...  def __init__(self, props={}): 
...    self.props = props 
... 
>>> class b(a): 
...  def __init__(self, val = None): 
...    super(b, self).__init__() 
...    self.props.update({'arg': val}) 
... 
>>> class c(b): 
...  def __init__(self, val): 
...    super(c, self).__init__(val) 
... 
>>> b_inst = b(2) 
>>> b_inst.props 
{'arg': 2} 
>>> c_inst = c(3) 
>>> c_inst.props 
{'arg': 3} 
>>> b_inst.props 
{'arg': 3} 
>>> 

在調試階段,在第二個電話(c(3))你可以看到, a構造函數self.props已經等於{'arg': 2},並且在構造函數b之後被調用時,它將變爲{'arg': 3}這兩個對象!

也,構造函數調用的順序是:

a, b # for b(2) 
    c, a, b # for c(3) 

如果你在b構造改變self.props.update()self.props = {'arg': val},一切都會好起來,並如預期

但我真的需要將採取行動到更新這個屬性,不能代替

+0

這是繼承問題,還是「默認參數值被評估爲一次」問題? – 2009-09-02 14:04:46

+0

謝謝,用'None'代替'{}'幫助了我。 – 2009-09-02 14:10:26

+0

謝謝,漢克,我已經重新命名了這個問題 – 2009-09-02 14:11:37

回答

9

props不應該有一個這樣的默認值。代之以:

class a(object): 
    def __init__(self, props=None): 
     if props is None: 
      props = {} 
     self.props = props 

這是一個常見的python "gotcha"

7

你的問題是在這一行:

def __init__(self, props={}): 

{}是一個可變類型。而在python中,默認參數值只會被評估一次。這意味着你的所有實例都共享相同的字典對象!

爲了解決這個問題將其更改爲:

class a(object): 
    def __init__(self, props=None): 
     if is None: 
      props = {} 
     self.props = props 
+0

不要做「如果不是道具」,布爾虛假值可以打破該行 – 2009-09-02 14:11:01

+0

@Gorgapor,你說得對,沒有更準確的。我會解決我的答案。 – 2009-09-02 14:12:49

1

短的版本:操作:

class a(object): 
    def __init__(self, props=None): 
     self.props = props if props is not None else {} 

class b(a): 
    def __init__(self, val = None): 
     super(b, self).__init__() 
     self.props.update({'arg': val}) 

class c(b): 
    def __init__(self, val): 
    super(c, self).__init__(val) 

長版本:

函數定義是完全評估一次,所以每次你怎麼稱呼它相同的默認參數時使用。爲了達到您的預期效果,每次調用函數時都必須對默認參數進行評估。但相反,Python生成一次函數對象並將默認值添加到對象(如func_obj.func_defaults