我正在尝试实现一个二阶装饰器,它将动态变量注入作为装饰函数的第一个参数。
这是我到目前为止所拥有的:
from typing import Callable, Concatenate, ParamSpec, TypeVar
T = TypeVar('T')
U = TypeVar('U')
P = ParamSpec('P')
def foo(some_arg: U) -> Callable[
[Callable[Concatenate[U, P], T]],
Callable[P, T],
]:
def decorator(fn: Callable[Concatenate[U, P], T]) -> Callable[P, T]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
return fn(some_arg, *args, **kwargs)
return wrapper
return decorator
运行mypy时,出现以下错误:
error: Incompatible return value type (
got "Callable[[Arg(Callable[[U, **P], T], 'fn')], Callable[P, T]]",
expected "Callable[[Callable[[U, **P], T]], Callable[P, T]]") [return-value]
我不明白我做错了什么。 我找不到 Mypy 所说的有关
Arg
元素的任何信息(在 mypy 文档中找不到 typing.Arg
)。
我应该如何声明我的装饰器工厂的返回值? 我应该如何解释 mypy 的此错误输出?我可能错过了文档中的任何来源吗?
正如 @STerliakov 已经提到的,这很可能是一个错误。 但据我所知, mypy 遇到的困惑是,您指定返回带有一个未命名参数的可调用对象,而返回第一个参数称为
fn
的函数。这不是一个错误,因为您也可以按位置传递可选的命名参数(因此这是一个错误)。
如果您当前无法升级 mypy,使
fn
成为必须的位置参数(通过在签名中添加 /
),可能会解决您的问题:
def decorator(fn: Callable[Concatenate[U, P], T], /) -> Callable[P, T]:
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
return fn(some_arg, *args, **kwargs)
return wrapper
return decorator