Как решить проблему «Несовместимый тип возвращаемого значения (перегруженная функция)» - PullRequest
1 голос
/ 17 июня 2019

Я пытаюсь определить функцию, которая возвращает другую функцию.Возвращаемая функция перегружена.

Например:

from typing import overload, Union, Callable

@overload
def foo(a: str) -> str:
    pass
@overload
def foo(a: int) -> int:
    pass
def foo(a: Union[str, int]) -> Union[str, int]:
    if isinstance(a, int):
        return 1
    else:
        # str
        return "one"

def bar() -> Callable[[Union[str, int]], Union[str, int]]:
    return foo # Incompatible return value type (got overloaded function, expected "Callable[[Union[str, int]], Union[str, int]]")

Однако мой ввод для функции bar выдается как ошибка с использованием Mypy.

Как правильно набрать bar?Что я делаю не так?

1 Ответ

2 голосов
/ 17 июня 2019

Проблема здесь частично заключается в том, что тип Callable слишком ограничен для точного выражения типа для foo, а также в том, что mypy в настоящее время очень консервативен при анализе совместимости перегрузок с Callables.(Это трудно сделать в общем случае).

Вероятно, лучший подход на данный момент - просто определить более точный тип возврата с помощью Протокол обратного вызова и вернуть его вместо этого:

Например:

from typing import overload, Union, Callable

# Or if you're using Python 3.8+, just 'from typing import Protocol'
from typing_extensions import Protocol

# A callback protocol encoding the exact signature you want to return
class FooLike(Protocol):
    @overload
    def __call__(self, a: str) -> str: ...
    @overload
    def __call__(self, a: int) -> int: ...
    def __call__(self, a: Union[str, int]) -> Union[str, int]: ...


@overload
def foo(a: str) -> str:
    pass
@overload
def foo(a: int) -> int:
    pass
def foo(a: Union[str, int]) -> Union[str, int]:
    if isinstance(a, int):
        return 1
    else:
        # str
        return "one"

def bar() -> FooLike:
    return foo  # now type-checks

Примечание: Protocol был добавлен в модуль typing начиная с Python 3.8.Если вы хотите использовать его в более ранних версиях Python, установите typing_extensions module ( pip install typing_extensions`) и импортируйте его оттуда.

Необходимость дважды копировать подпись, по общему признанию, немного неуклюжа.Обычно люди сходятся во мнении, что это проблема (существуют различные проблемы в , набрав и mypy средства отслеживания ошибок), но я не думаю, что есть какое-то согласие относительно того, каклучше всего решить это.

...