2011-05-16 97 views
6

可能重複:
「Least Astonishment」 in Python: The Mutable Default Argument的Python:字典爲實例變量

我對字典的類的實例變量的出現在Python 3的行爲我的理解是很迷茫,Python中的實例變量具有每個實例存儲的,不同於每個類的類變量(類似於一些其他語言稱爲「靜態」)。

這似乎成立,除非實例變量是從默認參數創建的字典。例如:

class Foo: 
    def __init__(self, values = dict()): 
     self.values = values 

f1 = Foo() 
f1.values["hello"] = "world" 

f2 = Foo() 
print(f2.values) 

此程序輸出:

{'hello': 'world'} 

咦?爲什麼實例f2f1具有相同的字典實例?

我得到預期的行爲,如果我沒有在一個空的字典作爲默認的參數傳遞,只是分配self.values明確一個空的字典:

class Foo: 
    def __init__(self): 
     self.values = dict() 

但我不明白爲什麼這應該有什麼區別。

+1

這可能是因爲默認參數只會在加載類時評估一次。這樣,你只是分配相同的參考作爲默認參數。 – 2011-05-16 17:28:40

+0

堆棧溢出每個標記都有一個很好的「常見問題」功能。以下是Python標記的常見問題解答:http://stackoverflow.com/questions/tagged/python?sort=faq&pagesize=30您的問題在問題編號4處得到解答。 – 2011-05-16 18:30:35

回答

10

這是Python中衆所周知的驚喜。當函數被定義時,而不是被調用時,默認參數被評估。所以你的默認參數是對一個共同的dict的引用。它與分配給類/實例變量無關。

如果您想使用默認參數,使用None,並檢查它:

if values is None: 
    self.values = {} 
else: 
    self.values = values 
+1

您將在列表中獲得相同的行爲 – jaydel 2011-05-16 17:30:54

+2

您將獲得與每個*可變對象相同的行爲。 – delnan 2011-05-16 17:50:36

2

默認值只計算一次。你想要的東西是這樣的:

class Foo: 
    def __init__(self, values = None): 
     self.values = values or dict() 

如果你提供values,那會被使用。如果不是,則valuesor運算符評估爲FALSE,並實例化新的字典。

+2

如果有任何虛假信息作爲值傳遞,這會失敗 - 例如,一個自定義的'dict'子類的空實例。 – delnan 2011-05-16 18:02:16