给已有代码加类型注解:从 0 到 mypy 通过
给已有代码加类型不是“全量重写”,而是先把边界钉死,再逐步向内收紧。
一、从边界开始
# 先给公开函数与数据结构加类型
def load_orders(path: str) -> list[dict[str, object]]:
...
# 再给内部关键路径加
def total(amounts: Iterable[Decimal]) -> Decimal:
return sum(amounts, Decimal("0"))入口(API、CLI、数据库读取)和出口(返回值)先标;内部实现允许推断,避免一上手就被 Any 淹没。
二、mypy 渐进式配置
# mypy.ini
[mypy]
python_version = 3.8
ignore_missing_imports = True
disallow_untyped_defs = False
warn_unused_ignores = True
show_error_codes = True
[mypy-app.core.*]
disallow_untyped_defs = True先全局宽松、对核心模块单独严格,让 CI 只对新增代码卡门;等核心模块干净了再扩大范围。
三、常见误报怎么处理
- 第三方库没有 stub → 装
types-*包,或写最小.pyi - 字典取值类型太宽 → 用
TypedDict描述结构 - 联合类型收窄困难 →
isinstance前置,或cast加注释说明理由
小结
类型注解的价值在“改动时能不能立刻发现破了哪里”。先覆盖边界,再谈覆盖率百分比。