求助:Mypy为何无法识别父NamedTuple中定义的number属性
Mypy无法识别Fava/Beancount中Amount类型的number属性问题
问题场景
项目基于Fava(依赖Beancount)开发,已通过mypy.ini的mypy_path配置让Mypy读取本地Fava存根文件,配置确认生效。编写函数如下:
def get_units(postings: list[Posting]): numbers = [] for posting in postings: numbers.append(posting.units.number) return numbers
运行类型检查命令mypy src时,出现错误:
report.py:4 error: Item "type" of "Union[Amount, Type[MISSING]]" has no attribute "number" [union-attr]
已确认:
- Fava存根中
Posting的units标注为Amount类型 Amount继承自Beancount的_Amount类,number属性在Fava存根中有定义
但Mypy仍报错找不到number属性,原因是什么?
原因分析
- 类型定义冲突:Mypy实际识别到的
units类型是Union[Amount, Type[MISSING]],而非存根中标注的单纯Amount。这大概率是因为Mypy同时加载了Beancount原生的类型定义和Fava存根,两者对units的类型标注不一致,合并后引入了Type[MISSING]分支。 - 存根继承关系未正确识别:如果Fava存根中没有明确标注
Amount继承_Amount的number属性,或者_Amount的存根未被Mypy纳入扫描范围,会导致类型推断时无法关联到number属性。 - Mypy类型合并逻辑:当同一模块存在多份类型定义(如存根文件和源码类型提示),Mypy会合并类型信息,若其中一份定义引入了可选的
MISSING类型分支,就会触发union-attr错误——因为Type[MISSING]确实没有number属性。
解决办法
1. 显式类型断言
在访问number属性前,通过类型断言排除Type[MISSING]分支,让Mypy明确当前units是Amount类型:
from beancount.core.amount import Amount def get_units(postings: list[Posting]): numbers = [] for posting in postings: assert isinstance(posting.units, Amount), "Posting units must be an Amount" numbers.append(posting.units.number) return numbers
2. 调整存根文件优先级
检查mypy.ini的mypy_path配置,确保Fava存根文件的路径排在Beancount源码路径之前,让Mypy优先加载Fava的存根定义,避免和原生类型冲突:
[mypy] mypy_path = ./path/to/fava/stubs:./path/to/beancount/source
3. 补全存根类型信息
如果Fava存根中Amount类的number属性未明确标注,手动在存根文件中补充该属性的类型定义:
# 在fava/stubs/beancount/core/amount.pyi中 from decimal import Decimal from beancount.core.amount import _Amount class Amount(_Amount): number: Decimal currency: str
内容的提问来源于stack exchange,提问作者Vahid
相关产品推荐
相关产品推荐

