MyPy在Callable
*args
和**kwargs
方面存在一些问题,特别是有关装饰器的问题,详见:https://github.com/python/mypy/issues/1927
具体来说,对于没有参数只包装函数(并且不更改其签名)的装饰器,您需要以下内容:
from typing import Any, Callable, cast, TypeVar
FuncT = TypeVar('FuncT', bound=Callable[..., Any])
def print_on_call(func: FuncT) -> FuncT:
def wrapped(*args, **kwargs):
print("Running", func.__name__)
return func(*args, **kwargs)
return cast(FuncT, wrapped)
最后的cast()
应该是不必要的(MyPy应该能够通过在func
末尾调用wrapped
来确定包裹的确是FuncT -> FuncT
)。我可以忍受这个,直到它被修复。
然而,当您引入带参数的装饰器时,这会破坏性。考虑装饰者:
def print_on_call(foo):
def decorator(func):
def wrapped(*args, **kwargs):
print("Running", foo)
return func(*args, **kwargs)
return wrapped
return decorator
使用的是:
@print_on_call('bar')
def stuff(a, b):
return a + b
我们可能会尝试输入它(使用Guido认可的无参数示例作为指导),如下所示:
from typing import Any, Callable, Dict, List, TypeVar
FuncT = TypeVar('FuncT', bound=Callable[..., Any])
def print_on_call(foo: str) -> Callable[[FuncT], FuncT]:
def decorator(func: FuncT) -> FuncT:
def wrapped(*args: List[Any], **kwargs: Dict[str, Any]) -> Any:
print("Running", foo)
return func(*args, **kwargs)
return cast(FuncT, wrapped)
return cast(Callable[[FuncT], FuncT], decorator)
这似乎是类型检查,但是当我们使用它时:
@print_on_call('bar')
def stuff(a: int, b: int) -> int:
return a + b
我们遇到了一个令人讨厌的错误:
error: Argument 1 has incompatible type Callable[[int, int], int]; expected <uninhabited>
我对这怎么可能感到有点困惑。如PEP 484中所述,似乎Callable[[int, int], int]
应该是Callable[..., Any]
的子类型。
我认为这可能是在print_on_call
的返回类型和aa参数以及返回类型decorator
之间使用泛型之间的错误迭代,因此我将我的示例简化为最低限度(虽然不再是一个工作装饰者,但仍然应该进行类型检查):
from typing import Any, Callable, Dict, List, TypeVar
FuncT = TypeVar('FuncT', bound=Callable[..., Any])
def print_on_call(foo: str) -> Callable[[FuncT], FuncT]:
return cast(Callable[[FuncT], FuncT], None)
然而,这仍会导致上述错误。只需#type: ignore
即可,这是我可以做的事情,但不幸的是,由于这个问题,装饰这个装饰器的任何函数都有类型<uninhabited>
,所以你开始失去类型安全性无处不在。
所有人都说(tl; dr):
如何使用参数键入装饰器(不修改函数的签名)?上面是一个bug吗?可以解决吗?
MyPy版本:0.501(此帖子的最新版本)
答案 0 :(得分:1)
糟糕!看起来我没有足够的搜索。已存在问题和解决方法:https://github.com/python/mypy/issues/1551#issuecomment-253978622
答案 1 :(得分:0)
现在,这是由 mypy 直接支持的:
https://mypy.readthedocs.io/en/stable/generics.html#declaring-decorators
即
im[7, 3] = 0.80913063