Python:带固定位置参数与*args/**kwargs的Callable类型提示(mypy报错解决)
适配mypy 0.812版本的带固定位置参数+可变参数函数类型提示方案
报错根源
你之前写Callable[[str, ...], None]触发的Unexpected '...'报错,本质是版本兼容问题:
Callable[[str, ...], None]这种在固定参数后面拼接...的语法,是Python 3.10才正式纳入typing规范的新写法,作用是标记“第一个参数为str,后续的可变位置参数、可变关键字参数不做严格类型校验”。- 你当前使用的mypy 0.812是2021年发布的旧版本,对应Python 3.9及更早的类型规范,在这个版本的检查规则里,
...作为参数通配符只能出现在Callable参数列表的最开头,也就是仅支持Callable[..., ReturnType]这种“完全不校验所有参数类型”的写法,绝对不允许把...夹在固定参数列表中间,因此会直接抛出语法不支持的错误。
兼容当前版本的正确写法
根据你对类型校验强度的需求,可以选择以下几种可通过mypy 0.812检查的方案:
- 方案1:不强制显式标注类型,直接靠类型推导匹配
直接执行foo_ = foo即可,mypy会自动完整推导foo的原始签名(包含第一个参数的str类型、后续*args和**kwargs的类型约束),不会触发任何报错,是最省事的写法。 - 方案2:简化的宽松类型标注
如果你不需要严格保留第一个参数的类型校验,仅需要标记这是个返回None的可调用对象,可以直接写foo_: Callable[..., None] = foo。这种写法可以通过语法检查,但会丢失对bar参数必须为str类型的约束。 - 方案3:完整保留签名约束的精确标注
如果你需要严格保留“第一个参数是str类型,后续支持任意数量可变位置、可变关键字参数”的校验要求,可以通过定义结构化Protocol的方式实现,这种写法完全兼容旧版mypy:
这种方式通过结构化子类型匹配规则,完整复刻了你需要的函数签名特征,既不会触发from typing import Any, Protocol class MatchedFooSignature(Protocol): def __call__(self, bar: str, *args: Any, **kwargs: Any) -> None: ... foo_: MatchedFooSignature = foo...相关的语法错误,也能实现和新版Callable[[str, ...], None]完全一致的类型校验效果。
补充说明:如果后续你升级mypy到0.9.x及以上的新版本,是可以直接使用
Callable[[str, ...], None]这种简洁写法的,但在当前0.812的版本下,这种写法属于不被识别的非法语法。
内容的提问来源于stack exchange,提问作者Intrastellar Explorer
相关产品推荐
相关产品推荐

