为什么尝试使用 `Callable` 别名 (`Alias=Callable`) 会在将其用作泛型时导致“参数数量错误”?

问题描述 投票:0回答:1

我在尝试类型提示时遇到了以下情况(第二个片段中的错误):

首先,没有任何别名,一切都通过类型检查:

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]): ...

为什么我的别名在第二个示例中不起作用?

与使用别名相比,我的解决方案对于简单别名(实际上不再是别名)来说似乎过于复杂。

注:

这些示例使用的工具和版本是:

  • Python 3.12
  • MyPy 1.10
python python-typing type-alias
1个回答
0
投票

事物就是这样定义的。

Callable
中的
MyCallableAlias = Callable
表示
Callable[..., Any]

您还需要使

MyCallableAlias
变得通用:

(游乐场链接:MypyPyright

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]
© www.soinside.com 2019 - 2024. All rights reserved.