在 Python 中键入一个可变参数函数
Typehint a variadic function in Python
我写了一个高阶python函数(姑且称之为parent
),它的参数函数(姑且称之为child
)是一个可变参数函数。
我不知道如何输入提示。
child
将始终是 str
的第一个参数和可变数量的参数作为参数,可以是任何参数。它returns Any
.
我能得到的最接近它的是 Callable[..., Any]
但后来我“失去”了第一个参数是 str
.
的事实
我想要这样的东西 Callable[[str,...], Any]
但这不是有效的类型提示。
有没有办法对我的函数进行类型提示?
使用 Protocol 不需要您手动将值包装在“类型提示包装器”中,但不幸的是它在这里对您没有帮助。
如果一个函数可以匹配一个协议,它的签名必须与协议中__call__
方法的签名完全匹配。但是,(如果我没记错的话)你想匹配任何函数与一个字符串作为第一个参数,它可以是以下任何一个:
def fn1(x: str) -> Any: ...
def fn2(x: str, arg1: int, arg2: float) -> Any: ...
def fn3(x: str, *args: Any, **kwargs: Any) -> Any: ...
这些都有不同的签名,因此无法通过单一协议匹配:(mypy-play)
from typing import Any, Protocol
# This might be the protocol you might use, but unfortunately it doesn't work.
class StrCallable(Protocol):
def __call__(self, x: str, *args, **kwargs) -> Any:
...
def my_higher_order_fn(fn: StrCallable) -> StrCallable:
return fn # fill this with your actual implementation
my_higher_order_fn(fn1) # fails
my_higher_order_fn(fn2) # fails
my_higher_order_fn(fn3) # this passes, though
PEP 612 引入了 ParamSpec
,这是您在这里需要的。它有点像 TypeVar
,但用于函数签名。您可以在 Callable
:
中放置第一个列表参数的地方放置 ParamSpec
from typing import Callable, Concatenate, ParamSpec, TypeVar
P = ParamSpec("P")
TRet = TypeVar("TRet")
StrCallable = Callable[Concatenate[str, P], TRet]
其中 Concatenate
将类型连接到现有参数规范。 Concatenate[str, P]
正是您所需要的:第一个参数为 str
.
的任何函数签名
不幸的是,PEP 612 直到 Python 3.10 才可用,而且 mypy 还没有完全支持它。在那之前,您可能只需要使用 Callable[..., TRet]
.
我写了一个高阶python函数(姑且称之为parent
),它的参数函数(姑且称之为child
)是一个可变参数函数。
我不知道如何输入提示。
child
将始终是 str
的第一个参数和可变数量的参数作为参数,可以是任何参数。它returns Any
.
我能得到的最接近它的是 Callable[..., Any]
但后来我“失去”了第一个参数是 str
.
我想要这样的东西 Callable[[str,...], Any]
但这不是有效的类型提示。
有没有办法对我的函数进行类型提示?
使用 Protocol 不需要您手动将值包装在“类型提示包装器”中,但不幸的是它在这里对您没有帮助。
如果一个函数可以匹配一个协议,它的签名必须与协议中__call__
方法的签名完全匹配。但是,(如果我没记错的话)你想匹配任何函数与一个字符串作为第一个参数,它可以是以下任何一个:
def fn1(x: str) -> Any: ...
def fn2(x: str, arg1: int, arg2: float) -> Any: ...
def fn3(x: str, *args: Any, **kwargs: Any) -> Any: ...
这些都有不同的签名,因此无法通过单一协议匹配:(mypy-play)
from typing import Any, Protocol
# This might be the protocol you might use, but unfortunately it doesn't work.
class StrCallable(Protocol):
def __call__(self, x: str, *args, **kwargs) -> Any:
...
def my_higher_order_fn(fn: StrCallable) -> StrCallable:
return fn # fill this with your actual implementation
my_higher_order_fn(fn1) # fails
my_higher_order_fn(fn2) # fails
my_higher_order_fn(fn3) # this passes, though
PEP 612 引入了 ParamSpec
,这是您在这里需要的。它有点像 TypeVar
,但用于函数签名。您可以在 Callable
:
ParamSpec
from typing import Callable, Concatenate, ParamSpec, TypeVar
P = ParamSpec("P")
TRet = TypeVar("TRet")
StrCallable = Callable[Concatenate[str, P], TRet]
其中 Concatenate
将类型连接到现有参数规范。 Concatenate[str, P]
正是您所需要的:第一个参数为 str
.
不幸的是,PEP 612 直到 Python 3.10 才可用,而且 mypy 还没有完全支持它。在那之前,您可能只需要使用 Callable[..., TRet]
.