Проблема здесь частично заключается в том, что тип 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 средства отслеживания ошибок), но я не думаю, что есть какое-то согласие относительно того, каклучше всего решить это.