如何为接受至少一个参数的可调用对象添加类型提示?
为接受至少一个参数的可调用对象添加类型提示
两种可行方案
方案一:用Callable直接约束(仅适用于位置参数场景)
如果你的可调用对象只需要接受至少一个位置参数,可以直接用Callable[[object, ...], 返回类型]的写法。这里的object, ...表示第一个参数为任意类型,后面可以跟任意数量的额外参数,直接排除了无参函数。
示例代码:
from typing import Callable # 定义接受至少一个位置参数、返回int的可调用类型 CallableWithAtLeastOneArg = Callable[[object, ...], int] def foo(x: int) -> int: return x + 1 def bar(x: int, y: float) -> int: return int(x + y) class Baz: def __call__(self, x: int) -> int: return x * 2 def noargs() -> int: return 0 # 测试函数,参数必须是符合要求的可调用对象 def process(func: CallableWithAtLeastOneArg) -> None: result = func(42) print(result) # 合法调用 process(foo) process(bar) process(Baz()) # 类型检查会报错(noargs不接受任何参数) # process(noargs)
方案二:用Protocol自定义协议(支持更复杂场景)
如果需要支持仅接受关键字参数的可调用对象,或者需要更精确的参数类型约束,推荐用typing.Protocol定义自定义协议。
示例1:约束至少一个位置参数
from typing import Protocol, TypeVar R = TypeVar("R", covariant=True) class CallableWithAtLeastOnePosArg(Protocol[R]): def __call__(self, arg: object, *args: object, **kwargs: object) -> R: ... # 使用示例 def process(func: CallableWithAtLeastOnePosArg[int]) -> None: func(42) # 合法调用同上,noargs会被类型检查拒绝
示例2:约束至少一个关键字参数
如果要支持像def qux(*, x: int) -> int: ...这种仅接受关键字参数的函数,可以定义另一个协议:
class CallableWithAtLeastOneKwArg(Protocol[R]): def __call__(self, *, arg: object, **kwargs: object) -> R: ... def qux(*, x: int) -> int: return x * 3 # 测试 def process_kw(func: CallableWithAtLeastOneKwArg[int]) -> None: func(arg=42) process_kw(qux) # 合法 # process_kw(noargs) # 类型检查报错
示例3:同时支持两种情况
如果需要同时允许“至少一个位置参数”或“至少一个关键字参数”的可调用对象,可以用Union合并两个协议:
from typing import Union CallableWithAtLeastOneArg = Union[CallableWithAtLeastOnePosArg[R], CallableWithAtLeastOneKwArg[R]]
为什么之前的*args/**kwargs写法不对
你尝试的*args/**kwargs写法可能是Callable[..., 返回类型],但这个写法会包含无参函数(因为无参函数也能接受空的*args和**kwargs),无法满足你排除无参对象的需求。而如果错误地写成Callable[[*args, **kwargs], 返回类型],这本身是语法错误,不符合Callable的使用规范。
内容的提问来源于stack exchange,提问作者yuti
相关产品推荐
相关产品推荐

