【问题标题】:Should instances of a frozenset subclass be hashable in Python 3?在 Python 3 中,frozenset 子类的实例应该是可散列的吗?
【发布时间】:2015-01-08 02:06:31
【问题描述】:

根据https://docs.python.org/2/library/stdtypes.html#frozenset,在 Python 2 中:

frozenset 类型是不可变和可散列的——它的内容在创建后不能更改;但是,它可以用作字典键或另一个集合的元素。

但是根据https://docs.python.org/3.4/library/stdtypes.html#frozenset,在 Python 3 中,我看不到表明 freezeset 实例(或子类)应该是可散列的信息,只有 set/frozenset 元素:

集合元素,如字典键,必须是可散列的。

那么,以下代码是否应该适用于任何 Python 3 解释器,或者最后一行是否应该引发 TypeError

# Code under test
class NewFrozenSet(frozenset):
    def __eq__(self, other):
        return True

    # Workaround: Uncomment this override
    # def __hash__(self):
    #     return hash(frozenset(self))

hash(frozenset())
hash(NewFrozenSet())

OSX Yosemite 10.10,系统 python2

$ python
Python 2.7.6 (default, Sep  9 2014, 15:04:36)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class NewFrozenSet(frozenset):
...     def __eq__(self, other):
...         return True
...
>>> hash(frozenset())
133156838395276
>>> hash(NewFrozenSet())
133156838395276

OSX Yosemite 10.10,使用自制软件http://brew.sh/

$ brew install python3
$ python3
Python 3.4.2 (default, Jan  5 2015, 11:57:21)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.56)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class NewFrozenSet(frozenset):
...     def __eq__(self, other):
...         return True
...
>>> hash(frozenset())
133156838395276
>>> hash(NewFrozenSet())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'NewFrozenSet'
>>>

Ubuntu 14.04.1 LTS (x86_64),系统 python3

$ python3
Python 3.4.0 (default, Apr 11 2014, 13:05:11)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class NewFrozenSet(frozenset):
...     def __eq__(self, other):
...         return True
...
>>> hash(frozenset())
133156838395276
>>> hash(NewFrozenSet())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'NewFrozenSet'
>>>

TL;DR - 这是 Python 3 中的回归,还是经过深思熟虑的设计选择?

【问题讨论】:

    标签: python python-3.x hash frozenset


    【解决方案1】:

    来自hashable的定义:

    比较相等的可散列对象必须具有相同的散列值。

    您现在已经实现了一个新的__eq__ 方法,但没有为NewFrozenSet 实现一个新的__hash__。 Python 现在不能假设上述属性成立(即__eq____hash__ 的行为匹配),因此它不能假设该类型是可散列的。这就是为什么您需要同时实现 __eq____hash__ 以使类型可散列(或者不实现任何一个并使用父类中的方法)。

    例如,如果你省略了__eq__,那么NewFrozenSet 就变成了可散列的:

    class NewFrozenSet(frozenset):
        pass
    

    如果这在您的 NewFrozenSet 中不正确,那么您需要同时实现 __eq____hash__

    【讨论】:

      猜你喜欢
      • 2013-09-25
      • 2012-11-02
      • 1970-01-01
      • 2021-09-30
      • 1970-01-01
      • 2021-04-05
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多