Наследование - __hash__ устанавливает в None в подклассе - PullRequest
0 голосов
/ 28 ноября 2018

Мне удалось воспроизвести это на 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()

Очевидно, можно ожидать, что здесь будет определено 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

То же поведение воспроизводится при реализации __init__ как super().__init__() в Comparable и A.

1 Ответ

0 голосов
/ 28 ноября 2018

Нашел его в документах :

Классу, который переопределяет __eq__() и не определяет __hash__(), для его __hash__() будет неявно установлено значение Нет.

и

Если класс, который переопределяет __eq__(), должен сохранить реализацию __hash__() от родительского класса, интерпретатор должен сказать это явно, установив__hash__ = <ParentClass>.__hash__

Из билета 1549 :

Это было сделано намеренно - если вы определяете сравнение без определения хэша, хэш по умолчаниюне будет соответствовать вашему сравнению, и ваши объекты будут плохо работать при использовании в качестве словарных ключей.

(Гвидо ван Россум)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...