2011-06-10 63 views
44

我偶然發現了一篇博文,詳細介紹瞭如何在Python中實現powerset函數。所以我嘗試着用我自己的方式去做,並發現Python顯然不能有一組集合,因爲集合不可散列。這很令人厭煩,因爲powerset的定義是它是一組集合,我想用實際集合操作來實現它。爲什麼Python集不可散列?

>>> set([ set() ]) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'set' 

是否有一個很好的理由Python集不可哈希?

+3

任何不可改變的東西通常都會導致錯誤的關鍵。如果必須的話,你可以使用元組。 – 2011-06-10 18:59:29

回答

81

通常,Python中只有不可變對象是可散列的。 set() - frozenset()的不可變變體 - 可散列。

+5

請參閱Python FAQ條目[爲什麼字典鍵必須是不可變的?](http://docs.python.org/3.3/faq/design。HTML#爲什麼,必須詞典密鑰待不變)。 – abarnert 2013-05-18 01:05:13

22

因爲它們是可變的。

如果它們是可散列的,散列可能會默默地變成「無效」,而這幾乎使散列毫無意義。

15

從Python文檔:

可哈希
一個目的是可哈希如果 具有散列值在其壽命期間,其從不改變 (它需要一個 散列()方法)並且可以與其他對象進行比較(它需要 eq()或cmp()方法)。比較相等 的可哈希對象必須具有相同的哈希值。

Hashability使得可用作 字典密鑰和一組構件, 一個對象,因爲這些數據結構使用 散列值在內部。

所有Python的不可變的內置 對象是可哈希的,而沒有可變 容器(如列表或 字典)是。對象是 用戶定義類的實例默認爲可散列的 ;他們都比較 不相等,他們的散列值是他們的 id()。

4

在這種情況下幫助......如果你真的需要unhashable東西轉換成哈希的等效由於某種原因,你可能會做這樣的事情:

from collections import Hashable, MutableSet, MutableSequence, MutableMapping 

def make_hashdict(value): 
    """ 
    Inspired by https://stackoverflow.com/questions/1151658/python-hashable-dicts 
    - with the added bonus that it inherits from the dict type of value 
     so OrderedDict's maintain their order and other subclasses of dict() maintain their attributes 
    """ 
    map_type = type(value) 

    class HashableDict(map_type): 
     def __init__(self, *args, **kwargs): 
      super(HashableDict, self).__init__(*args, **kwargs) 
     def __hash__(self): 
      return hash(tuple(sorted(self.items()))) 

    hashDict = HashableDict(value) 

    return hashDict 


def make_hashable(value): 
    if not isinstance(value, Hashable): 
     if isinstance(value, MutableSet): 
      value = frozenset(value) 
     elif isinstance(value, MutableSequence): 
      value = tuple(value) 
     elif isinstance(value, MutableMapping): 
      value = make_hashdict(value) 

     return value 

my_set = set() 
my_set.add(make_hashable(['a', 'list'])) 
my_set.add(make_hashable({'a': 1, 'dict': 2})) 
my_set.add(make_hashable({'a', 'new', 'set'})) 

print my_set 

我HashableDict實現是最簡單和最嚴格的例如從here。如果您需要更高級的支持酸洗和其他功能的HashableDict,請檢查其他許多實現。在我上面的版本中,我想保留原始的dict類,從而保留OrderedDicts的順序。我還使用here的AttrDict進行屬性類訪問。

我上面的示例沒有任何權威性,只是我解決類似問題的方法,我需要將一些內容存儲在一個集合中,並需要首先對它們進行「哈希」。

相關問題