You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助: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属性,原因是什么?

原因分析

  1. 类型定义冲突:Mypy实际识别到的units类型是Union[Amount, Type[MISSING]],而非存根中标注的单纯Amount。这大概率是因为Mypy同时加载了Beancount原生的类型定义和Fava存根,两者对units的类型标注不一致,合并后引入了Type[MISSING]分支。
  2. 存根继承关系未正确识别:如果Fava存根中没有明确标注Amount继承_Amount的number属性,或者_Amount的存根未被Mypy纳入扫描范围,会导致类型推断时无法关联到number属性。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 19:31:15