这与 Typing function when decorator change return type 类似,但这次具有通用返回类型:
from typing import Generic, TypeVar, Generic, Callable, Any, cast
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self, item: T):
self.item: T = item
def my_decorator(f: Callable[..., T]) -> Callable[..., Container[T]]:
def wrapper(*args: Any, **kwargs: Any) -> Container[T]:
return Container(f(*args, **kwargs))
return cast(Callable[..., Container[T]], wrapper)
@my_decorator
def my_func(i: int, s: str) -> bool: ...
reveal_type(my_func) # Revealed type is 'def (*Any, **Any) -> file.Container[builtins.bool*]
要保持 my_func
的参数类型完整,需要哪种 mypy 法术?
使用 typing.Protocol
看起来很有希望,但我不知道如何让它发挥作用。
答案 0 :(得分:1)
使用 Callable[..., T]
是目前最好的注释方式。
PEP 612 引入了 ParamSpec
,它的用法类似于 TypeVar
,可以解决您的问题。它目前计划用于 Python 3.10,并将支持使用 typing_extensions
你会写:
T = TypeVar('T')
P = ParamSpec('P')
def my_decorator(f: Callable[P, T]) -> Callable[P, Container[T]]:
def wrapper(*args: Any, **kwargs: Any) -> Container[T]:
return Container(f(*args, **kwargs))
return cast(Callable[P, Container[T]], wrapper)
mypy 对 PEP 612 的支持尚未完成:https://github.com/python/mypy/issues/8645。与 pytype(Google 的 python 类型检查器)相同。
pyright(微软的 python typechecker)和 pyre(facebook 的 python typechecker)已经支持 PEP 612