继承 - __hash__在子类中设置为None

Dee*_*ace 4 python inheritance

我设法在Python 3.4和3.7上重现了这一点.

考虑:

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()
Run Code Online (Sandbox Code Playgroud)

显然,人们期望b.__hash__在这里定义,因为它定义在Comparable哪个B子类下.

瞧,它被定义,但评估为None.是什么赋予了?

>> 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
Run Code Online (Sandbox Code Playgroud)

如果在和中实现__init__,则会再现相同的行为.super().__init__()ComparableA

kab*_*nus 7

文档中找到它:

覆盖__eq__()和未定义的类__hash__()__hash__()隐式设置为None.

如果覆盖的类__eq__()需要保留__hash__()父类的实现,则必须通过设置明确告知解释器__hash__ = <ParentClass>.__hash__

1549号机票:

这是故意完成的 - 如果您定义比较而不定义哈希,则默认哈希将与您的比较不匹配,并且当您用作词典键时,您的对象将会出错.

(Guido van Rossum)