Python 类型标注入门

类型注解描述接口契约,默认不在运行时强制;配合静态检查器提升可维护性。

#type / concept #status / growing #tech / dev #resource / python #tech / lang / python

[!info] 关联笔记

Python 类型标注入门

这个概念为什么出现

动态类型利于快写,但公共接口缺少契约时,重构与协作成本上升。类型标注让工具(Pyright/mypy)在运行前发现不匹配,同时保留运行时灵活。

[!abstract] 一句话理解 注解是可选的静态契约:def f(x: int) -> str 描述意图,解释器默认不检查,静态检查器与文档受益。

最小可运行示例

先把示例放进业务场景,再看代码:

场景:定价函数明确入参出参,可选折扣

# pricing_typing.py
# 业务意图:计算折后价(分)。
# 教学点:
# - 参数/返回注解;
# - X | None 可选;
# - 注解不阻止错误实参在运行时进入(无检查器时)。

def price_after_discount(price_cents: int, discount: float | None = None) -> int:
    if discount is None:
        return price_cents
    if not 0 <= discount <= 1:
        raise ValueError("discount out of range")
    return int(price_cents * (1 - discount))


def main() -> None:
    print(price_after_discount(1000))
    print(price_after_discount(1000, 0.1))


if __name__ == "__main__":
    main()

建议运行:

python pricing_typing.py

期望输出:

1000
900

结合场景再看三个关注点

  1. 注解提高可读性:调用方知 discount 是 0–1 比例。
  2. 运行时仍靠 ValueError 守边界。
  3. price_after_discount("1000") 交给类型检查器会报警,但裸 python 可能到运算才失败。

核心概念与准确模型

写法含义
list[str]字符串列表(3.9+ 内置泛型)
dict[str, int]映射
X | Y联合(3.10+)
Optional[X]X | None
TypeVar/Generic泛型库 API
Callable[[int], str]可调用
  • from __future__ import annotations 推迟求值
  • typing.cast / assert / 运行时校验库(Pydantic)是另一层

边界情况与反直觉行为

  1. 注解可写错而程序仍运行。
  2. 字符串前向引用与延迟注解。
  3. 动态构造难被静态模型覆盖。

常见误区

[!warning] 常见误区:有注解就不需要测试 错误理解:类型代替行为验证。
正确模型:类型抓结构,测试抓行为。

工程实践

  • 公共 API 先标满
  • CI 跑 pyright/mypy
  • 渐进标注老代码

本节总结

类型标注是工程加速器,不是第二套运行时。与检查器一起用才完整。

自测题

  1. 注解会改变运行时分发吗?
  2. float | None 表达什么?
参考答案
  1. 默认不会。
  2. 要么 float,要么缺失 None。

延伸阅读与资料来源

资料类型支撑内容
typing文档类型系统库
PEP 484PEPType Hints
创建于 2026/7/15 更新于 2026/7/15