如何用Python Typing定义支持可选关键字参数的可调用类型?
解决方案
你之前的Protocol定义因为额外添加了**kwargs: Any,导致mypy强制要求函数必须能接受任意关键字参数,但add_one不支持任何关键字参数,因此触发类型错误。以下是两种符合需求的定义方式:
方案1:直接使用Callable类型
如果只需要保证函数可以通过f(a:int)的方式调用(无论函数是否带有其他可选关键字参数),直接用Callable[[int], int]即可。这个类型会自动兼容所有能接受单个int参数(包括带默认值关键字参数的函数)并返回int的函数:
from typing import Callable def call(a: int, f: Callable[[int], int]) -> int: return f(a) def add_one(a: int) -> int: return a + 1 def add_one_and_b(a: int, b: int = 1) -> int: return a + 1 + b call(1, add_one) # 正常通过mypy检查 call(1, add_one_and_b) # 正常通过mypy检查
方案2:使用Protocol定义
如果你偏好使用Protocol,只需要在__call__中描述实际调用时的参数即可——也就是仅声明a:int,不需要额外的**kwargs。因为Protocol的__call__是描述你调用函数的方式,而非函数的完整签名:
from typing import Protocol class CallableWithIntParam(Protocol): def __call__(self, a: int) -> int: ... def call(a: int, f: CallableWithIntParam) -> int: return f(a) def add_one(a: int) -> int: return a + 1 def add_one_and_b(a: int, b: int = 1) -> int: return a + 1 + b call(1, add_one) # 正常通过mypy检查 call(1, add_one_and_b) # 正常通过mypy检查
特殊需求:强制函数支持任意可选关键字参数
如果你的需求是函数必须能接受a:int加上任意额外的关键字参数(比如调用时可能传入f(a=1, extra=2)),可以这样定义Protocol:
from typing import Protocol, Any class CallableWithIntAndOptionalKwargs(Protocol): def __call__(self, a: int, **kwargs: Any) -> int: ...
注意:这种定义下add_one会不兼容(因为它不接受任何关键字参数),仅适用于必须支持额外关键字参数的场景。
内容的提问来源于stack exchange,提问作者Vince
相关产品推荐
相关产品推荐

