我正在尝试注释“compose”函数的类型,但我无法让 mypy 告诉我我错了。
在下面的代码中,first 和 eval 的定义按预期工作,将返回类型更改为(比如说)int 会给我一个错误。
但是,compose 的定义却不然。我可以将结果函数的返回值更改为几乎任何值,而 mypy 不会注意到它。
应该是这样吗?我可以做什么来进行类型检查以检查特定类型?
from typing import Sequence, TypeVar, Callable
T = TypeVar('T')
S = TypeVar('S')
H = TypeVar('H')
def first(l: Sequence[T], h : Sequence[S]) -> tuple[T,S]:
return (l[0],h[0])
def eval(f : Callable[[T],S], arg : T) -> S :
return f(arg)
def compose (f : Callable[[T],S], g : Callable[[H],T]) -> Callable[[H],int]: #no complaints?
def aux(x):
a = g(x)
b = f(a)
return b
return aux
ParamSpec
。
from typing import Callable, TypeVar, ParamSpec
T = TypeVar('T')
S = TypeVar('S')
P = ParamSpec('P')
def compose(f: Callable[[S], T], g: Callable[P, S]) -> Callable[P, T]:
def _composed(*args: P.args, **kwargs: P.kwargs) -> T:
a = g(*args, **kwargs)
b = f(a)
return b
return aux
当然,如果您只是将一个参数硬编码到组合函数中,则不需要
ParamSpec
— 只需 TypeVar
就足够了:
from typing import Callable, TypeVar
T = TypeVar('T')
S = TypeVar('S')
R = TypeVar('R')
def compose(f: Callable[[S], R], g: Callable[[T], S]) -> Callable[[T], R]:
def _composed(arg: T) -> R:
a = g(arg)
b = f(a)
return b
return aux
更大的挑战是将其推广为可变参数
compose
。 Python 的类型提示系统在变量方面非常有限。据我所知,目前唯一的方法是使用 typing.overload
为每个数量定义单独的类型提示。例如,这是我在 compose
库的类型存根中所做的操作:
from typing import Callable, ParamSpec, TypeVar, overload
P = ParamSpec('P')
R1 = TypeVar('R1')
R2 = TypeVar('R2')
R3 = TypeVar('R3')
# and so on up to whatever arity you want to support.
@overload
def compose(f1: Callable[P, R1], /) -> Callable[P, R1]:
...
@overload
def compose(f2: Callable[[R1], R2], f1: Callable[P, R1], /) -> Callable[P, R2]:
...
@overload
def compose(f3: Callable[[R2], R3], f2: Callable[[R1], R2], f1: Callable[P, R1], /) -> Callable[P, R3]:
...
# and so on up to whatever arity you want to support.