Inheritance - __hash__ sets to None in a subclass

耗尽温柔 提交于 2020-05-13 05:06:14

问题


I managed to reproduce this on both Python 3.4 and 3.7.

Consider:

class Comparable:
    def _key(self):
        raise NotImplementedError

    def __hash__(self):
        return hash(self._key())

    def __eq__(self, other):
        ...

    def __lt__(self, other):
        ...


class A(Comparable): pass

class B(A):
    def __str__(self):
        return "d"

    def __eq__(self, other):
        return isinstance(self, type(other))

    def _key(self):
        return str(self),

b = B()

Clearly one would expect b.__hash__ to be defined here, since it is defined under Comparable which B is a subclass of.

Lo and behold, it is defined, but evaluates to None. What gives?

>> b
<__main__.B object at 0x00000183C9734978>
>> '__hash__' in dir(b)
True
>> b.__hash__

>> b.__hash__ is None
True
>> B.__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class '__main__.Comparable'>, <class 'object'>)
>> isinstance(b, Comparable)
True

The same behavior is reproduced if implementing __init__ as super().__init__() in Comparable and A.


回答1:


Found it in the docs:

A class that overrides __eq__() and does not define __hash__() will have its __hash__() implicitly set to None.

and

If a class that overrides __eq__() needs to retain the implementation of __hash__() from a parent class, the interpreter must be told this explicitly by setting __hash__ = <ParentClass>.__hash__

From ticket 1549:

This was done intentionally -- if you define a comparison without defining a hash, the default hash will not match your comparison, and your objects will misbehave when used as dictionary keys.

(Guido van Rossum)



来源:https://stackoverflow.com/questions/53518981/inheritance-hash-sets-to-none-in-a-subclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!