我在尝试类型提示时遇到了以下情况(第二个片段中的错误):
from typing import Callable
T = TypeVar("T") # Invariant by default
P = ParamSpec("P")
def some_decorator(f: Callable[P, T]): ... # Passes type checking
from typing import Callable, TypeVar, ParamSpec
T = TypeVar("T") # Invariant by default
P = ParamSpec("P")
MyCallableAlias = Callable
# error: Bad number of arguments for type alias, expected 0, given 2 [type-arg]
def my_decorator(f: MyCallableAlias[P, T]): ...
我不太明白这一点,因为我希望
MyCallableAlias
的行为与 Callable
完全一样。
Protocol
:
from typing import Protocol, TypeVar, ParamSpec, Generic
# Using the default variance (invariant) causes an error at type checking.
T = TypeVar("T", covariant=True)
P = ParamSpec("P")
class MyCallableAlias(Generic[P, T], Protocol):
def __call__(self, *args: P.args, **kwargs: P.kwargs): ...
def my_decorator(f: MyCallableAlias[P, T]): ...
为什么我的别名在第二个示例中不起作用?
与使用别名相比,我的解决方案对于简单别名(实际上不再是别名)来说似乎过于复杂。
注:
这些示例使用的工具和版本是:
事物就是这样定义的。
Callable
中的MyCallableAlias = Callable
表示Callable[..., Any]
。
您还需要使
MyCallableAlias
变得通用:
P = ParamSpec('P')
R = TypeVar('R')
MyCallableAlias = Callable[P, R]
def some_decorator(f: MyCallableAlias[P, T]) -> MyCallableAlias[P, T]:
...
在3.12+中,语法更加直观:
type MyCallableAlias[**P, R] = Callable[P, R]