Переменные аргументы с mypy: сигнатура метода, несовместимого с супертипом

Я не совсем понимаю, почему mypy возвращает здесь ошибку Signature of "foo" is incompatible with supertype "Base". Кажется, что возвращаемые типы и типы аргументов совпадают.

from typing import NoReturn, Union


class Base():
    def foo(self, *args: str) -> Union[NoReturn, str]:
        raise NotImplementedError


class A(Base):
    def foo(self, x: str) -> str:
        return x

Любая помощь приветствуется, спасибо!

ИЗМЕНИТЬ Я изменил A.foo на следующее:

def foo(self, *args: str) -> str:
    x = args[0]
    return x

Теперь ошибка mypy исчезла. Однако в этой реализации не возникнет ли та же проблема, если в Base есть NoReturn, а переопределенная функция может вернуть только str?


person mmhl    schedule 08.03.2019    source источник


Ответы (2)


Разница небольшая. Итак, я объясню, что каждый делает

def foo(self, *args: str) -> Union[NoReturn, str]:

foo - это метод экземпляра класса Base, который принимает переменное количество строковых аргументов и возвращает либо NoReturn, либо str.

def foo(self, x: str) -> str:

foo - это метод экземпляра класса A, который отменяет определение foo в классе Base. Он принимает единственный аргумент str и возвращает единственный str

Это означает, что я могу назвать версию Base как foo('bar', 'baz'), но тот же вызов в A вызовет ошибку.

Точно так же у меня не может быть возврата в Base, в то время как вызов переопределенной функции возвращает только str

Проблема здесь в том, что функция имеет другое поведение и тип, но одно и то же имя, что вводит в заблуждение.

person Skam    schedule 08.03.2019
comment
Извините, я понимаю, о чем вы говорите. Итак, я изменил A.foo на это: def foo(self, *args: str) -> str: \n\t x = args[0] \n\t return x Теперь ошибка mypy исчезла. Однако в этой реализации не возникнет ли та же проблема, если в Base есть NoReturn, переопределенная функция может вернуть только str? - person mmhl; 09.03.2019
comment
Можете ли вы добавить это к исходному вопросу вместо публикации в комментарии? - person Skam; 09.03.2019
comment
Я добавил отформатированную версию вопроса к исходному сообщению - person mmhl; 09.03.2019

Без вашего EDIT у вас есть проблема, описанная @Skam: https://stackoverflow.com/a/55071593/369009

С РЕДАКТИРОВАТЬ все в порядке. Подумайте об этом коде:

bs: Base = A() # bs is of type Base
return_value = bs.foo('test') # Return value is of type `Union[NoReturn, str]`

При вызове bs.foo мы выражаем возвращаемое значение либо NoReturn, либо str. A всегда возвращает str, но это нормально, поскольку str также является частью Union[NoReturn, str], поэтому это всегда верно. Любой, кто вызывает foo в базовом классе, должен обрабатывать оба возвращаемых типа, а A просто всегда возвращает только str и никогда NoReturn.

Только если бы все было наоборот, это было бы проблемой: если предположить, что A вернет Union, а Base вернет str, тогда вызывающие Base.foo могут неожиданно получить NoReturn, когда ожидали только str.

person Jan Rüegg    schedule 10.12.2019