【问题标题】:Why aren't Python sets hashable?为什么 Python 集合不可散列?
【发布时间】:2011-09-12 17:50:30
【问题描述】:

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

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

Python 集合不可散列是否有充分的理由?

【问题讨论】:

  • 任何不可变的东西通常都会导致坏密钥。如果需要,您可以使用元组。

标签: python hash set


【解决方案1】:

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

【讨论】:

【解决方案2】:

因为它们是可变的。

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

【讨论】:

    【解决方案3】:

    来自 Python 文档:

    可散列
    一个对象是可散列的,如果它 有一个永远不会改变的哈希值 在其生命周期内(它需要一个 hash() 方法),并且可以与其他对象进行比较(它需要一个 eq() 或 cmp() 方法)。比较相等的可散列对象 必须具有相同的哈希值。

    Hashability 使对象可用作 字典键和集合成员, 因为这些数据结构使用 内部哈希值。

    所有 Python 的不可变内置 对象是可散列的,而不是可变的 容器(例如列表或 字典)是。对象是 用户定义类的实例是 默认情况下可散列;他们都比较 不相等,它们的哈希值是它们的 id()。

    【讨论】:

      【解决方案4】:

      如果这有帮助...如果您出于某种原因确实需要将不可散列的东西转换为可散列的等价物,您可能会这样做:

      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 进行类似属性的访问。

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

      【讨论】:

      • 由于sorted,这需要对值进行排序。有些对象定义了__eq____hash__,但没有定义订单(__le__ 等)。你可以改用hash(frozenzet(self.items()))
      猜你喜欢
      • 2015-07-10
      • 1970-01-01
      • 2018-09-02
      • 2010-12-29
      • 2020-03-30
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      相关资源
      最近更新 更多