是否应该在Python 3中使用冻结子类的实例?

时间:2015-01-08 02:06:31

标签: python python-3.x hash frozenset

根据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中的回归,还是故意的设计选择?

1 个答案:

答案 0 :(得分:1)

根据hashable的定义:

  

比较相等的Hashable对象必须具有相同的哈希值。

您现在已为__eq__实施了新的__hash__方法,但未实施NewFrozenSet新方法。 Python现在不能假设上述属性成立(即__eq____hash__的行为匹配),因此它不能假定该类型是可清除的。这就是为什么您需要同时实现__eq____hash__以使类型可以清除(或者不实现并使用父类中的方法)的原因。

例如,如果您遗漏__eq__,那么NewFrozenSet会变得可以播放:

class NewFrozenSet(frozenset):
    pass

如果NewFrozenSet中的内容不正确,则需要同时实施__eq____hash__