为什么Python集合不能散列?

2nc8po8w  于 2023-01-19  发布在  Python
关注(0)|答案(4)|浏览(227)

我偶然发现了一篇博客文章,详细介绍了如何在Python中实现powerset函数,于是我开始尝试自己的方法,发现Python显然不能有集合的集合,因为集合是不可哈希的。这很烦人,因为powerset的定义是集合的集合,而我想使用实际的集合操作来实现它。

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

Python集合不可散列有什么好的理由吗?

hsgswve4

hsgswve41#

通常,在Python中只有不可变对象是可哈希的,set()的不可变变体--frozenset()--是可哈希的。

sc4hvdpw

sc4hvdpw2#

因为它们是可变的。
如果它们是可散列的,那么散列可能会悄悄地变得“无效”,这几乎会使散列变得毫无意义。

eulz3vhy

eulz3vhy3#

来自Python文档:

可哈希

如果一个对象的哈希值在其生存期内从未改变(它需要一个hash()方法),并且可以与其他对象进行比较(它需要一个eq()或cmp()方法),则该对象是可哈希的。比较相等的可哈希对象必须具有相同的哈希值。
哈希性使对象可以用作字典键和集成员,因为这些数据结构在内部使用哈希值。
所有Python的不可变内置对象都是可散列的,而没有可变容器(如列表或字典)是可散列的。默认情况下,用户定义类的示例对象是可散列的;它们比较起来都不相等,并且它们的散列值是它们的id()。

bmp9r5qi

bmp9r5qi4#

如果你真的需要把不可哈希的东西转换成可哈希的等价物,你可以这样做:

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中最简单和最不严格的例子。如果你需要一个更高级的支持pickle和其他东西的HashableDict,检查许多其他的实现。在我上面的版本中,我希望保留原始的dict类,从而保留OrderedDict的顺序。我还使用here中的AttrDict进行类似属性的访问。
我上面的例子在任何方面都不是权威的,只是我对一个类似问题的解决方案,我需要在一个集合中存储一些东西,并需要首先“哈希化”它们。

相关问题