2010-01-10 51 views
1

我試圖構建一組對象的實例,但是添加某些對象的實例導致TypeError: unhashable instance。下面是一個小例子:實例集

from sets import Set 
import random 
from UserDict import DictMixin 

class Item1(object): 
    pass 

class Item2(DictMixin): 
    pass 

item_collection = Set() 

x = Item1() 
y = Item2() 

item_collection.add(x) # this works 
print item_collection 
item_collection.add(y) # this does not 
print item_collection 

爲什麼失敗,我怎麼能得到一組從DictMixin派生的對象的實例?

回答

4

如果您願意,您的課程可以定義__hash__和比較方法(最重要的是__eq__)彼此一致和「穩定」 - 即兩個對象的相等性不得隨着對象的生命期而變化,當然,每個對象的散列值在對象的整個生命週期內都不會變化。

一致性的要求是:a==b必須暗示hash(a)==hash(b)(反向不必抱,確實很少做)。

所以,如果你確定了這些要求最簡單的實現將是:

class Item2(DictMixin): 
    def __hash__(self): return hash(id(self)) 
    def __eq__(self, x): return x is self 
    def __ne__(self, x): return x is not self 

,因爲它發生,這也將自動與您Item1類互操作,因爲這是散列和比較的默認實現不繼承或定義其他版本的類(因爲除非重新覆蓋它,否則將從DictMixin繼承__eq__的不同版本)。

x is selfid(x) == id(self)更快,更直接,更簡潔的表達,因爲該is操作者的意思 - id(即,相同的對象)的身份。

那麼,事實上,a==b被迫與您的應用程序的a is b問題意味着相同的事情?如果是這樣,那麼集合對於所述應用程序不可用,並且您需要考慮其他一些完全不同的數據結構(不基於散列的數據結構,因爲如果沒有__eq__覆蓋,則無法使散列工作正確)。

+0

使用'id'生成哈希是否有缺點?我在這裏問了一下http://stackoverflow.com/questions/2040101/using-object-id-as-a-hash-for-objects-in-python,因爲這是我想到的新東西。 – 2010-01-11 05:38:45

5

爲了把東西放到一個集合中,它們應該是可散列的。例如元組是可哈希的,而列表不是。你可以通過給它一個__hash__方法來讓你的對象成爲可散列的方法,它會爲它產生一個散列鍵(這個類的實例依賴於它所持有的數據的唯一標識符)。

這是一個嘗試向列表添加列表的示例。

>>> x = [1,2,3] 
>>> a=set() 
>>> a.add(x) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

它看起來像你的DictMixin類是不可散的。

+0

我該如何實現它?我不希望散列依賴於它所持有的數據,而是我希望該集合的每個條目都是對特定實例的引用,而不管它可能會更改的數據如何。類似於用C語言指向實例的指針, – pysnake 2010-01-10 18:37:04

+0

該集合的良好查找特性是通過散列它所包含的對象來獲得的。這就要求對象是可散列的,因爲幾乎不可能查找對象,除非你有辦法將它們轉換成散列。這是可變類型的原因,例如列表不能放入集合中。您可以嘗試使用創建對象的'id'作爲哈希值。我從來沒有嘗試過,我不確定這是不是一個好主意。你確定你想要一套嗎?列表不行嗎? – 2010-01-10 18:41:54

+0

我需要集合的元素是唯一的,需要測試成員資格,所以列表看起來不正確。使用id聽起來很直觀,但我不想在沒有理解所有後果的情況下做類似的事情。任何其他建議更適合的數據類型?基本上我需要一個指向一個具有唯一成員資格和快速查找的對象實例的指針集合。 – pysnake 2010-01-10 18:51:48