Python 类型注解是渐进式类型系统:运行时不做任何校验,价值全在 mypy/pyright 静态检查与 IDE 提示。

基本注解

# 变量
count: int = 0
ratios: list[float] = []
 
# 函数签名
def scale(data: list[float], k: float = 1.0) -> list[float]:
    return [x * k for x in data]

PEP 604 起 X | Y 取代 Union[X, Y],可空类型写 X | None(取代 Optional[X]):

def find(name: str) -> dict[str, int] | None: ...
 
# Python 3.9 及以下的等价写法
from typing import Optional
def find(name: str) -> Optional[dict[str, int]]: ...

容器泛型

3.9+ 直接用内建容器作泛型,不再需要 typing.List:

from typing import Any
 
matrix: list[list[float]] = []
cache: dict[str, Any] = {}
ids: tuple[int, ...] = (1, 2, 3)   # 定长 tuple[int, str],变长用 ...

泛型函数:TypeVar

from typing import TypeVar
 
T = TypeVar("T")
 
def first(seq: list[T]) -> T:      # 输出类型与输入元素类型绑定
    return seq[0]

TypeVar 让检查器追踪「输入输出类型相同」这类约束;TypeVar("N", bound=float) 可设上界,多个具体 TypeVar 可表达协变关系。

Callable / TypedDict / Literal

from typing import Callable, TypedDict, Literal
 
# 可调用对象:参数类型 + 返回类型
handler: Callable[[str, int], bool]
 
# 键与值类型都受限的字典
class Point(TypedDict):
    x: float
    y: float
 
# 只允许字面取值,适合模式/开关类参数
Mode = Literal["train", "eval", "predict"]
 
def run(mode: Mode) -> None: ...
run("train")   # OK
run("fit")     # mypy 报错

Protocol:结构化类型

协议与抽象基类 走显式继承做 nominal typing;Protocol 只看结构有没有那个方法——鸭子类型的静态化:

from typing import Protocol
 
class Closeable(Protocol):
    def close(self) -> None: ...
 
def shutdown(res: Closeable) -> None:   # 任何有 close() 的对象都匹配
    res.close()

运行时不校验

注解只是元数据,存于 __annotations__,解释器不检查:

def add(a: int, b: int) -> int:
    return a + b
 
add("1", "2")   # 照样运行,返回 "12"

需要运行时强制校验用 Pydantic;注解配合 数据类 dataclass 则能消除手写 __init__ 的样板。

from future import annotations

模块顶部加这一行后,所有注解延迟求值、以字符串存储(PEP 563),前向引用不再需要引号:

from __future__ import annotations
 
class Node:
    def next(self) -> Node | None: ...   # Node 未定义完即可引用

mypy、pyright 才是注解的真正消费者:本地 IDE 实时检查,CI 里接入静态检查即获得接近静态语言的类型安全。