Основная проблема заключается в том, что метод __eq__
должен принимать любой объект: выполнение my_object == 3
допустимо во время выполнения и всегда должно возвращать False.Вы можете убедиться в этом сами, проверив определение базового типа для object
в Typeshed : подпись __eq__
задана как def __eq__(self, o: object) -> bool: ...
Итак, чтобы сделать этодля работы, правильный способ реализации __eq__
заключается в следующем:
def __eq__(self, other: object) -> bool:
if not isinstance(other, Person):
# If we return NotImplemented, Python will automatically try
# running other.__eq__(self), in case 'other' knows what to do with
# Person objects.
return NotImplemented
return self.id == other.id
И фактически, если вы обновите версию mypy, которую вы используете, она напечатает примечание с рекомендациейВы структурируете свой код таким образом.
Однако проблема этого подхода в том, что mypy теперь больше не будет жаловаться, если вы сделаете что-то глупое, как Person() == 3
.Технически это должно возвращать bool, но, прагматично, ваш код, вероятно, содержит ошибку, если вы сравниваете объект person с int.
К счастью, mypy совсем недавно получила функцию, которая может помечать эти видыошибки: --strict-equality
.Теперь, когда вы запустите mypy с этим флагом, выполнение Person() == 3
приведет к ошибкам вывода mypy, например Non-overlapping equality check (left operand type: "Person", right operand type: "int")
, даже если вы определите __eq__
описанным выше способом.
Обратите внимание, что вам нужно использоватьпоследняя версия mypy от master для использования этого флага, пока не будет выпущена следующая версия mypy (0.680).Это должно произойти примерно через 2-3 недели с момента написания.
Если определение __eq__
описанным выше способом не является чем-то, что вы можете сделать по какой-либо причине, я лично рекомендую исключитьошибка типа вместо замены Person на Any
.
В общем, сделайте это:
def __eq__(self, other: 'Person') -> bool: # type: ignore
return self.id == other.id
... возможно, вместе с кратким сообщением о том, почему вы подавляете ошибку.
Обоснование здесь состоит в том, что это определение __eq__
, строго говоря, является небезопасным (оно нарушает что-то, известное как принцип подстановки Лискова) - и если вам нужно сделать что-то небезопасное,вероятно, лучше явно указать, что вы подрываете систему типов, а не скрывать ее, используя Any.
И, по крайней мере, таким образом, вы все равно можете сделать выражения типа Person() == 3
ошибкой типа - еслиВы используете Any
, выражения типа Person() == 3
будут автоматически проверять тип.В этот момент вы можете просто использовать object
и структурировать свой код так, чтобы он вел себя правильно.