2

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

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

但是根据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 中的回归,还是经过深思熟虑的设计选择?

4

1 回答 1

2

hashable的定义:

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

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

例如,如果你省略__eq__thenNewFrozenSet确实变得可散列:

class NewFrozenSet(frozenset):
    pass

如果这在您的情况下不正确,NewFrozenSet那么您需要同时实现__eq__and __hash__

于 2015-01-08T09:45:23.397 回答