lin*_*k89 9 python python-3.x python-typing
考虑以下代码示例
def sum(a: int, b: int):
return a + b
def wrap(*args, **kwargs):
# delegate to sum
return sum(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
除了类型提示丢失之外,代码运行良好。*args, **kwargs在 Python 中用来实现委托模式是很常见的。如果有一种方法可以在使用它们时保留类型提示,那就太好了,但我不知道是否可能以及如何实现。
有关此问题的详细讨论,请参阅https://github.com/python/typing/issues/270 。您可以通过wrap使用适当类型的标识函数进行装饰来实现此目的:
F = TypeVar("F", bound=Callable)
def copy_signature(_: F) -> Callable[..., F]:
return lambda f: f
def s(x: int, y: int) -> int:
return x + y
@copy_signature(s)
def wrap(*args, **kwargs):
s(*args, **kwargs)
reveal_type(wrap) # Revealed type is "def (x: int, y: int) -> int"
Run Code Online (Sandbox Code Playgroud)
据我所知,装饰器是必要的 - 即使使用 PEP612,单独使用类型提示仍然不可能做到这一点。由于在这种情况下使用functools.wraps装饰器(复制运行时类型信息)已经是很好的实践,所以这并不是什么损失 - 您可以改为定义
def wraps(f: F) -> Callable[..., F]:
return functools.wraps(f) # type: ignore
Run Code Online (Sandbox Code Playgroud)
然后,只要您使用此装饰器,运行时和静态类型信息都应该是正确的。(遗憾的是,mypy 中包含的 typeshed 存根functools.wraps并没有足够的限制,无法开箱即用。)
PEP612 添加了在包装器中添加/删除参数的功能(通过与 结合ParamSpec)Concatenate,但它并没有消除对某种高阶函数(如装饰器)的需要,以让类型系统wrap从中推断出 的签名的s。