根据https://docs.python.org/2/library/stdtypes.html#frozenset,在Python 2中:
冻结类型是不可变的和可散列的 - 其内容在创建后不能更改;但是,它可以用作字典键或另一组的元素。
然而根据https://docs.python.org/3.4/library/stdtypes.html#frozenset,在Python 3中,我看不到任何信息表明冻结的实例(或子类)应该是可以清除的,只有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优胜美地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),system 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中的回归,还是故意的设计选择?
答案 0 :(得分:1)
根据hashable的定义:
比较相等的Hashable对象必须具有相同的哈希值。
您现在已为__eq__
实施了新的__hash__
方法,但未实施NewFrozenSet
新方法。 Python现在不能假设上述属性成立(即__eq__
和__hash__
的行为匹配),因此它不能假定该类型是可清除的。这就是为什么您需要同时实现__eq__
和__hash__
以使类型可以清除(或者不实现并使用父类中的方法)的原因。
例如,如果您遗漏__eq__
,那么NewFrozenSet
会变得可以播放:
class NewFrozenSet(frozenset):
pass
如果NewFrozenSet
中的内容不正确,则需要同时实施__eq__
和__hash__
。