Почему определение типов аргументов для __eq__ вызывает ошибку типа MyPy?

Я использую Python 3.5.1 и недавно выпущенный анализатор статических типов MyPy v0.4.1.

У меня есть более сложный код, который я сократил до этого простейшего возможного класса python, необходимого для воспроизведения ошибки:

class MyObject(object):
    def __init__(self, value: int=5) -> None:
        self.value = value

    def __eq__(self, other: MyObject) -> bool:
        return self.value == other.value

При запуске средства проверки типов mypy test.py возникает следующая ошибка:

test.py: note: In class "MyObject":
test.py:5: error: Argument 1 of "__eq__" incompatible with supertype "object"

Моя теория, основанная на этих документах, заключается в том, что __eq__ и __ne__ на объекте уже определены типы, которые конфликтуют с переопределением этих типов моим подклассом. Мой вопрос в том, как определить эти типы, чтобы убедиться, что __eq__ проверяется на соответствие выбранному мной типу.


person Nick Sweeting    schedule 31.05.2016    source источник


Ответы (3)


== должен принимать произвольные другие объекты, а не только объекты вашего типа. Если он не распознает другой объект, он должен вернуть NotImplemented:

class MyObject(object):
    def __init__(self, value: int=5) -> None:
        self.value = value

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, MyObject):
            return NotImplemented
        return self.value == other.value

NotImplemented не является экземпляром bool, но у mypy, похоже, для этого есть странный особый случай. Он хочет, чтобы возвращаемая аннотация была bool, и не жалуется на строку return NotImplemented.

Кроме того, если вам нужно обратиться к MyObject для подсказок типа внутри его собственного тела, вам нужно использовать строку 'MyObject' вместо MyObject. MyObject еще не существует.

person user2357112 supports Monica    schedule 01.06.2016
comment
Re: ссылаясь на MyObject внутри его собственного тела, я сделал это в другом месте своего кода без цитирования, и я не получаю ошибок от MyPy: github.com/pirate/py-data/blob/master/ - person Nick Sweeting; 01.06.2016
comment
@NickSweeting: Вы его запускали? Вы должны получить сообщение об ошибке при попытке запустить его. - person user2357112 supports Monica; 01.06.2016
comment
Ах, спасибо @ user2357112, я только попробовал его и не запустил. Изменение его на струны сработало. - person Nick Sweeting; 01.06.2016
comment
Я только что понял одну вещь: я никогда раньше не видел, чтобы функции возвращали типы исключений (а не raise их), является ли это стандартной практикой? - person Nick Sweeting; 21.06.2016
comment
@NickSweeting: NotImplemented - не исключение. Вы думаете о NotImplementedError. Возврат NotImplemented - это то, как вы сигнализируете, что ваш специальный метод не присваивает значение операции, поэтому Python должен попробовать метод другого объекта. Я слышал, что это возвращаемое значение вместо исключения из соображений скорости. - person user2357112 supports Monica; 21.06.2016

Вы правильно прочитали документацию - вам нужно дать методу (__eq__) ту же подпись, что и в базовом классе (object), или более разрешительную.

Причина этого в том, что, поскольку ваш MyObject является подтипом object, MyObject может быть передан везде, где ожидается _6 _..., что означает, что этот код может сравнивать его с любым другим object, и для проверки типов нет законного способа жаловаться. Итак, чтобы отразить это, ваш __eq__ должен быть написан так, чтобы ожидать любых object.

Что вы можете сделать, так это прямо в теле метода, проверить тип и вернуть (или вызвать исключение):

if not isinstance(other, MyObject):
  return False

Затем, как сказано в этих документах, Mypy достаточно умен, после этой проверки он узнает, что other является MyObject, и обработает его соответствующим образом.

person Greg Price    schedule 01.06.2016

Тест с использованием isinstance () работает только в том случае, если нет наследования, если есть, вам нужно либо переопределить eq в производных классах, либо использовать if type (self)! = Type (other)

person Rich Gooding    schedule 09.10.2020