Python 类型注解完全指南

Python 类型注解系统教程:基础类型、函数注解、Optional 与 Union、泛型、渐进式类型化策略,配合 Mypy 把动态语言写出静态语言的可靠。

最佳实践
并发任务的多路径协同插画

直接回答:Python 类型注解(type hints)是写在代码里的类型契约:不会由解释器自动强制校验(Python 仍是动态语言),但让 IDE 补全飞起、重构有底气,配合 Mypy/Pyright 在运行前抓住类型错误。 注解可以渐进添加,一个函数一个函数地来。

基础类型

name: str = "张三"
age: int = 28
price: float = 9.9
active: bool = True

tags: list[str] = ["python", "tutorial"]        # 3.9+ 内置泛型
scores: dict[str, int] = {"math": 95}
point: tuple[float, float] = (1.0, 2.0)
unique: set[int] = {1, 2, 3}

3.9 之后直接用 list[int],不用再 from typing import List。

函数注解

def greet(name: str, punct: str = "!") -> str:
    return f"你好, {name}{punct}"

参数类型、返回值类型各就各位。函数始终不返回有意义的值时标 -> None,可以显式 return None,也可以自然结束。若有时返回业务值、有时返回 None,应使用相应联合类型;声明了非 None 返回类型的路径则需遵守契约。

Optional 与 Union

def find_user(uid: int) -> str | None:        # 可能找不到
    ...

def parse(data: str | bytes) -> str:           # 多种类型都行
    ...

str | None(3.10+)等价于老式 Optional[str]。标注"可能为 None"的价值立竿见影——启用相应检查后,检查器能提示未经缩窄就使用可能为 None 的值;它不能消除所有运行时错误。

泛型与自定义类

from typing import TypeVar

T = TypeVar("T")

def first(items: list[T]) -> T:
    return items[0]

first([1, 2]).bit_count()     # 检查器知道这是 int
first(["a"]).upper()          # 这里知道是 str

class Stack[T]:               # 3.12+ 泛型类语法
    def push(self, item: T) -> None: ...
    def pop(self) -> T: ...

泛型让容器类与工具函数"保类型"——放进去什么,拿出来还是什么。

常用高级类型速查

from typing import Callable, Iterable, Literal, TypedDict, Protocol

handler: Callable[[int], str]            # 函数类型
items: Iterable[int]                     # 可迭代即可(最宽接口)
mode: Literal["fast", "safe"]            # 字面量枚举

class User(TypedDict):                   # 结构化字典
    name: str
    age: int

class Drawable(Protocol):                # 鸭子类型契约
    def draw(self) -> None: ...

渐进式类型化:存量项目的正确姿势

  1. 优先为新代码的函数边界添加有用的注解;
  2. 公共 API 与核心模块优先补注解(收益密度最高);
  3. 检查器配置从宽松起步,按模块收紧;
  4. CI 加"覆盖率只升不降"门禁;
  5. 没类型存根的第三方库,先 Any 或 # type: ignore 放行,别卡死推进。

渐进是特性不是妥协——Python 类型系统的设计哲学就是"你想多严就多严"。

常见问题(FAQ)

Q:注解会影响运行时性能吗?
A:解释器不会自动按注解校验每次调用,但保存和求值注解仍可能有成本。Python 3.14 默认延迟求值,并不等于零开销;运行时读取注解的框架可能执行求值或额外校验。

Q:所有代码都要注解吗?
A:函数签名(公共接口)必须;函数内部的局部变量靠推断即可,标注关键变量就够。过度注解和零注解一样不可取。

Q:运行时校验用什么?
A:类型注解本身不强制校验数据;运行时校验(用户输入、外部数据)用 Pydantic——两者搭档,各管一岸。

官方参考

本文基于官方文档整理,未进行运行时或性能测试。示例中的业务函数、数据模型和部署地址需结合项目补全;局部片段不等同于完整生产应用。

延伸阅读

获取专属方案

联系我们

加入社区

微信扫码
加入官方交流群

立即体验

在线开通,按量计费,真正的云服务!

立即开始

选择观测云版本

代码托管平台