如何解决python-attrs构造时的unexpected keyword argument问题并让mypy校验通过
问题原因
你遇到的类型报错是静态检查工具的特性导致的:mypy/pyright只能识别类的静态定义,感知不到你在运行时通过attr.s(these=...)给第三方类A动态添加的attrs字段与初始化逻辑。因此它处理子类B的继承关系时,不会把a识别为B的合法构造参数,而运行时因为动态修改已经生效,所以代码可以正常执行。
可行解决方法
下面几种方案都可以解决类型报错,你可以根据自己的场景选择:
方案1:子类显式声明继承字段(最简便)
attrs 20.1.0以上版本支持inherited=True参数,你可以在子类B中显式声明继承自父类的字段,不需要重复定义字段逻辑,就能让类型检查器识别该参数:
import attr class A: def __init__(self, a: int): self.a = a # 注意这里原有代码的type=str和A的原生定义冲突,要改为int保持类型一致 attr.s(these={ "a": attr.ib(type=int) }, init=True)(A) @attr.s(kw_only=True) class B(A): # 显式声明继承的a字段,类型检查器会自动识别为构造参数 a: int = attr.ib(inherited=True) b: int = attr.ib() if __name__ == "__main__": a = A(1) b = B(a=1, b=2) print(a) print(b)
修改后mypy/pyright都能正常识别B(a=1, b=2)的写法。
方案2:为第三方类A添加类型存根
如果你不想在每个子类中都显式声明继承字段,可以给第三方类A单独加类型存根文件,让静态检查器直接识别A是attrs类:
- 在你的项目根目录新建
stubs文件夹,在里面创建和第三方库路径对应的文件结构,比如A类在thirdparty.module里,就新建stubs/thirdparty/module.pyi - 存根文件内容如下:
import attr @attr.s class A: a: int = attr.ib()
- 在mypy配置文件
mypy.ini中添加存根路径配置:
[mypy] python_version = 3.8 mypy_path = stubs
配置完成后静态检查器会直接读取存根的定义,子类B不需要加额外代码就能正常识别a参数。
方案3:关闭单条语句的类型检查(临时妥协方案)
如果只是临时解决不想改代码结构,可以在报错的行加类型忽略注释,不推荐长期使用:
b = B(a=1, b=2) # type: ignore
内容的提问来源于stack exchange,提问作者Nico W.
相关产品推荐
相关产品推荐

