#python #decorator #python-decorators #mypy #typechecking
#python #декоратор #python-декораторы #mypy #проверка типов
Вопрос:
Моя последняя попытка написать декоратор, который принимает любую возможную функцию python и передает проверку mypy с --disallow-any-decorated
флагом, выглядела так:
from typing import Any, Callable, TypeVar
T = TypeVar('T')
def decorator(func: Callable[..., T]) -> Callable[..., T]:
def decorated(*args: Any, **kwargs: Any) -> Any:
print('decorated')
return func(*args, **kwargs)
return decorated
@decorator
def foo() -> int:
print('foo')
return 42
print(foo())
Однако он по-прежнему терпит неудачу с Type of decorated function contains type "Any" ("Callable[..., int]")
Что я делаю не так? Я также пытался использовать VarArg
и KwArg
из mypy_extensions
вместо ...
, но это не помогло.
Ответ №1:
Запрещает функции, которые имеют
Any
в своей подписи после преобразования декоратора.
...
Callable[..., T]
это способ сказать, что вызываемый объект принимает ноль или более Any
аргументов. Таким образом, даже если объявление не содержит Any
самого себя, оно все равно преобразуется в объявление, содержащее Any
.
Комментарии:
1. Да, я это понимаю. Есть ли у вас какое-либо решение, как аннотировать такой декоратор?
Ответ №2:
Используйте TypeVar, чтобы поглотить весь вызываемый объект, а не только возвращаемый тип. Затем вы разъясняете MyPy, что тип оформленной функции совпадает с исходной, освобождая его от необходимости беспокоиться «О, но возвращаемый тип здесь может быть практически любым».
Возможно, потребуется использовать приведение в конечной строке возврата.
FuncT = TypeVar(FuncT, bound=Callable)
def decorator(func: FuncT) -> FuncT:
...
return cast(FuncT, decorated)
Комментарии:
1. Спасибо за ответ. Я не могу протестировать это прямо сейчас, но, похоже, это может решить мою проблему.