关于哈希:为什么Python集不可以?

Why aren't Python sets hashable?

我偶然发现了一篇博客文章,详细介绍了如何在python中实现powerset函数。所以我尝试了我自己的方法,发现Python显然不能有一组集合,因为集合不可散列。这是令人讨厌的,因为powerset的定义是它是一组集合,我希望使用实际的集合操作来实现它。

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

python集不可散列有什么好的原因吗?


通常,在Python中,只有不可变的对象才是可哈希的。set()的不变变种--frozenset()是可以散列的。


因为它们是可变的。

如果它们是可散列的,散列可能会悄悄地变为"无效",这将使散列几乎毫无意义。


从python文档中:

hashable
An object is hashable if it
has a hash value which never changes
during its lifetime (it needs a
hash() method), and can be compared to other objects (it needs an
eq() or cmp() method). Hashable objects which compare equal
must have the same hash value.

Hashability makes an object usable as
a dictionary key and a set member,
because these data structures use the
hash value internally.

All of Python’s immutable built-in
objects are hashable, while no mutable
containers (such as lists or
dictionaries) are. Objects which are
instances of user-defined classes are
hashable by default; they all compare
unequal, and their hash value is their
id().


如果这有帮助…如果出于某种原因,您确实需要将不可缓存的内容转换为可哈希等价物,那么您可能会这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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实现是这里最简单、最不严格的例子。如果您需要一个更高级的hashabledict来支持pickle和其他功能,请检查其他许多实现。在上面的版本中,我希望保留原来的dict类,从而保留ordereddicts的顺序。我还使用这里的attrdict访问属性。

我上面的例子没有任何权威性,只是我对一个类似问题的解决方案,在这个问题中,我需要将一些东西存储在一个集合中,并且需要首先"散列"它们。