2016-12-31 75 views
2

我讀過列表不能被散列的字典鍵。 然而,自定義對象似乎是可變的還有:字典鍵:自定義對象vs列表

# custom object 
class Vertex(object): 
    def __init__(self, key): 
     self.key = key 

v = Vertex(1) 
v.color = 'grey' # this line suggests the custom object is mutable 

但是,與清單,它們可以被用來作爲字典鍵;爲什麼是這樣?難道我們不能僅僅在這兩種情況下散列某種類型的id(例如內存中對象的地址)?

+0

請注意,您的類沒有定義'__eq__'。 – o11c

回答

4

Why Lists can't be Dictionary Keys指出:

列爲字典鍵

這就是說,簡單的答案,爲什麼清單不能作爲字典鍵是列表不提供有效的散列方法。當然,顯而易見的問題是,「爲什麼不呢?」

考慮可以爲列表提供哪種散列函數。

如果列表按照id進行散列,給定Python的散列函數定義,這肯定是有效的 - 具有不同散列值的列表將具有不同的ID。但是列表是容器,而其他大多數操作都是這樣處理的。因此,通過它們的ID哈希表,而不是會產生意想不到的行爲,例如:

  1. 仰望不同列表具有相同的內容會產生不同的結果,即使比較具有相同內容的列表會顯示它們等同。

  2. 在字典查找中使用列表文字將毫無意義 - 它總會產生KeyError。

用戶定義類型的字典鍵的

怎麼樣的情況下,用戶定義類型?

默認情況下,所有用戶定義的類型都可用作缺省爲id(對象)的散列(對象)和缺省爲cmp(id(object1),id(object2))的cmp(object1,object2)的字典鍵。上面對列表討論了同樣的建議,結果令人不滿意。爲什麼用戶定義的類型不同?

  1. 在對象必須放置在映射中的情況下,對象標識通常比對象內容重要得多。

  2. 在對象內容確實很重要的情況下,可以通過重寫__hash____cmp____eq__來重新定義默認設置。

注意,它往往是更好的做法,當一個對象被與一個值,簡單地分配一個值作爲對象的屬性之一。