2012-12-31 50 views
3

可能重複:
「Least Astonishment」 in Python: The Mutable Default Argument爲什麼python字典在我啓動一個新的類實例時會記住前一個實例的值?

我有一些很奇怪,當我試圖寫一個類象下面這樣。在第3行,我必須將newdata的新副本放到self.data中,否則,當我啓動一個新的類實例時,前一個的值仍然會被類記住。請參見下面的例子,請注意唯一的區別在代碼的兩個版本上線3

class Pt(object):                
    def __init__(self,newdata={}):            
     self.data=newdata.copy()              
     if self.data == {}:              
      self._taglist = []             
     else:                 
      self._taglist = self.data.keys()          
    def add_tag(self,tag=None):             
     self.data[tag]={'x':[0,1,2,3,4]}           
     self._taglist.append(tag)            


In [49]: pt = Pt() 

In [50]: pt.add_tag('b') 

In [51]: pt.add_tag('a') 

In [52]: pt.data 
Out[52]: {'a': {'x': [0, 1, 2, 3, 4]}, 'b': {'x': [0, 1, 2, 3, 4]}} 

In [53]: pt2 = Pt() 

In [54]: pt2._taglist 
Out[54]: [] 

class Pt(object):                
    def __init__(self,newdata={}):            
     self.data=newdata              
     if self.data == {}:              
      self._taglist = []             
     else:                 
      self._taglist = self.data.keys()          
    def add_tag(self,tag=None):             
     self.data[tag]={'x':[0,1,2,3,4]}           
     self._taglist.append(tag)            

In [56]: pt = Pt() 

In [57]: pt.add_tag('a') 

In [58]: pt.add_tag('b') 

In [59]: pt._taglist 
Out[59]: ['a', 'b'] 

In [60]: pt2 = Pt() 

In [61]: pt2._taglist 
Out[61]: ['a', 'b'] 

In [62]: pt2.data 
Out[62]: {'a': {'x': [0, 1, 2, 3, 4]}, 'b': {'x': [0, 1, 2, 3, 4]}} 

我想第二種情況是因爲:兩個newdata和self.data參考到同一個對象(但是怎麼會發生這種情況,值應該從右向左而不是反向),所以當我使用「add_tag」方法更新self.data時,新數據也會更新。但是我認爲當我通過pt2 = Pt()啓動一個新實例時,新數據應該使用默認值({}),它是否仍然保留來自pt1的舊值?

+1

你不應該使用可變對象作爲默認值。 – Keith

回答

3

爲什麼和所有已在「Least Astonishment」 in Python: The Mutable Default Argument中得到很好的解釋。所以這裏只是一個快速幫助如何解決你的問題。

由於保留了默認參數對象,因此不應將可變對象用作默認參數值。相反,您應該定義一個固定值,通常爲None,作爲初始化默認對象的默認值。所以你的構造函數看起來像這樣:

def __init__(self, newdata=None): 
    if newdata is None: 
     newdata = {} 
    # ... 
+1

我不會說**從不**使用mutables作爲默認值。有時候,這正是你想要的行爲。 –

+0

@JerryB這似乎不太可能,但如果情況確實如此,您應該使用其他一些機制來訪問共享對象,而不是將其用作默認參數,因爲這顯然會讓人感到困惑。 – poke

+0

當然,這一定很罕見,我試圖給出的任何例子都是必然的。但罕見的情況與以往不一樣。就像我在80年代上大學時一樣,他們不停地敲打着「永遠不要使用goto!」但我還沒有處理任何**沒有轉到goto的語言,只是命名了其他內容,並且具有內置的限制/保護。 –

1

你的問題是你複製字典,你創建一個新的詞典具有相同的值。這意味着你的字典中的列表是相同的,所以當你修改它們時,它們會在你的所有字典中被修改。

你想要做的是copy.deepcopy() - 這不僅僅是複製字典,還要複製列表。

相關問題