未经审视的人生不值得过。
🚀 typing 模块
上一节介绍了类型注解的基础用法。本节深入 Python 标准库的 typing 模块——它是整个类型系统的核心工具箱,提供了函数签名、泛型、协议、字面量类型等丰富抽象。掌握 typing 是编写大型、健壮 Python 项目的基础,也是阅读主流框架(FastAPI、Pydantic、SQLAlchemy)源码的钥匙。
📌 本节要点
- Any/object:
Any关闭类型检查,object是所有类型基类,需窄化 - Callable:标注可调用对象,
Callable[[参数], 返回] - TypeVar/Generic:定义泛型,
bound限定子类,受限TypeVar限定取值 - ParamSpec(3.10+):捕获参数签名,装饰器类型注解的关键
- Literal:字面量类型,限定具体值
- Final:不可变绑定;ClassVar:类变量标注
- Protocol:结构化类型(鸭子类型的类型化)
- TypedDict:类型化字典,字典键有类型约束
- Annotated:类型之外附加元信息,被 Pydantic/FastAPI 利用
- Python 3.12+:
type语句和泛型类语法让泛型表达更简洁
typing 模块在持续演进。许多原本需要从 typing 导入的工具,在新版 Python 中有了更简洁的原生替代:
- Python 3.9:
list[int]取代List[int](PEP 585) - Python 3.10:
X | Y取代Union[X, Y](PEP 604) - Python 3.12:
type语句取代TypeAlias(PEP 695)
本教程面向 Python 3.12+,优先使用新语法,但仍会介绍 typing 中的经典工具。
Any、NoReturn、Never
Any:任意类型
Any 表示"任意类型",相当于关闭类型检查——任何类型都与 Any 兼容:
类型系统层级关系:
from typing import Any
def process_anything(data: Any) -> Any:
# 不做任何类型约束,运行时不报错
return data
x: Any = 10
x = "hello" # Any 可以赋值为任何类型,检查器不警告
print(process_anything(42))
Any 是类型安全的"逃生舱",使用它等于放弃类型检查。应尽量用更具体的类型或 object。object 是所有类型的基类,但与 Any 不同——object 的方法很少,类型检查器会强制做窄化:
def process_object(data: object) -> None:
# data.upper() # 类型检查器报错:object 没有 upper 方法
if isinstance(data, str):
print(data.upper()) # 收窄为 str 后才能调用
优先用 object 表达"未知类型",用 Any 表达"明确放弃类型检查"。
NoReturn 与 Never
NoReturn 标注"函数永不返回"——它要么抛异常,要么无限循环:
from typing import NoReturn, Never
def fail(message: str) -> NoReturn:
"""总是抛出异常,永不返回。"""
raise RuntimeError(message)
def infinite_loop() -> NoReturn:
"""死循环,永不返回。"""
while True:
pass
# Never 是 Python 3.11+ 引入的,语义更精确
# NoReturn 是 Never 的旧别名
def unreachable() -> Never:
raise AssertionError("这行代码不应该被执行到")
NoReturn 和 Never 几乎等价,都表示"函数不正常返回"。Never(Python 3.11+,PEP 664)是更现代的写法,语义上更清晰——它表示"该类型没有值",可用于更广泛的场景(如穷尽检查)。
Callable:可调用对象
Callable 标注函数、lambda、实现了 __call__ 的对象等可调用物:
from typing import Callable
# Callable[[参数类型列表], 返回类型]
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
print(apply(lambda x, y: x + y, 3, 5)) # 8
print(apply(max, 3, 5)) # 5
# 不带参数的 Callable:Callable[[], int]
def get_counter() -> Callable[[], int]:
count = 0
def counter() -> int:
nonlocal count
count += 1
return count
return counter
c = get_counter()
print(c(), c(), c()) # 1 2 3
不限参数的 Callable
...(省略号)表示"任意参数签名":
# 接受任意参数,返回 int
def log_and_call(func: Callable[..., int], *args, **kwargs) -> int:
print(f"调用 {getattr(func, '__name__', 'callable')}")
return func(*args, **kwargs)
print(log_and_call(int, "42")) # 调用 int / 42
类本身也是可调用对象(调用类会创建实例)。Callable[[str, int], Person] 可以表示一个接收 str 和 int、返回 Person 的类或工厂函数。
Iterable、Iterator、Generator
Iterable 表示"可迭代对象"(实现了 __iter__),Iterator 表示"迭代器"(实现了 __iter__ 和 __next__):
from typing import Iterable, Iterator
def sum_all(numbers: Iterable[int]) -> int:
"""对任意可迭代对象求和。"""
return sum(numbers)
print(sum_all([1, 2, 3])) # 6
print(sum_all((x for x in range(5)))) # 10
print(sum_all({1, 2, 3})) # 6
def first(iterator: Iterator[int]) -> int | None:
"""取迭代器的第一个元素。"""
return next(iterator, None)
print(first(iter([1, 2, 3]))) # 1
Generator
Generator 标注生成器,签名为 Generator[YieldType, SendType, ReturnType]:
from typing import Generator
def counter(start: int, stop: int) -> Generator[int, None, str]:
"""生成 start 到 stop 的数字,最后返回 "done"。"""
for i in range(start, stop):
yield i
return "done"
gen = counter(1, 4)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# 再 next 会抛 StopIteration("done")
Generator[Y, S, R] 中:
Y:yield表达式产出的值的类型S:send()方法传入的值的类型(不用send则为None)R:生成器结束时的返回值类型(return语句的值)
普通的 yield 生成器,SendType 和 ReturnType 通常为 None,可简写为 Generator[int, None, None]。
TypeVar:类型变量
TypeVar 用于定义泛型类型变量,让函数的多个参数或返回值共享同一个"占位类型":
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T | None:
"""返回列表第一个元素,保持元素类型。"""
return items[0] if items else None
print(first([1, 2, 3])) # 1,类型推断为 int | None
print(first(["a", "b"])) # a,类型推断为 str | None
print(first([3.14, 2.71])) # 3.14,类型推断为 float | None
没有 TypeVar,first 只能标注为 list[object] -> object | None,丢失了"输入列表元素类型与返回值类型一致"的信息。TypeVar 让类型检查器能精确追踪这种关系。
受限 TypeVar
TypeVar 可以限定取值范围:
from typing import TypeVar
# 只能是 int 或 float
Number = TypeVar("Number", int, float)
def add(a: Number, b: Number) -> Number:
return a + b
print(add(1, 2)) # 3
print(add(1.5, 2.5)) # 4.0
# add("a", "b") # 类型检查器报错:str 不在 Number 的取值范围
# 约束 TypeVar:必须是某个类的子类
class SignalProcessor:
"""信号处理器基类。"""
def process(self, signal: list[float]) -> list[float]:
return signal
class LowPassFilter(SignalProcessor):
def process(self, signal: list[float]) -> list[float]:
# 简单低通滤波:移动平均
result = []
for i in range(len(signal)):
window = signal[max(0, i - 1):i + 2]
result.append(sum(window) / len(window))
return result
class HighPassFilter(SignalProcessor):
def process(self, signal: list[float]) -> list[float]:
# 简单高通滤波:当前值减去移动平均
result = []
for i in range(len(signal)):
window = signal[max(0, i - 1):i + 2]
avg = sum(window) / len(window)
result.append(signal[i] - avg)
return result
SP = TypeVar("SP", bound=SignalProcessor)
def apply_filter(processor: SP, signal: list[float]) -> list[float]:
"""应用信号处理器,保持处理器类型。"""
return processor.process(signal)
# 使用
lp = LowPassFilter()
hp = HighPassFilter()
data = [0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0]
print(apply_filter(lp, data)) # 平滑后的信号
print(apply_filter(hp, data)) # 高频分量
Generic:泛型类
Generic 让自定义类成为泛型类,可以像 list[T] 那样使用:
from typing import Generic, TypeVar
import numpy as np
T = TypeVar("T")
class SignalBuffer(Generic[T]):
"""泛型信号缓冲区,元素类型由 T 决定。"""
def __init__(self, capacity: int) -> None:
self._capacity = capacity
self._items: list[T] = []
def push(self, item: T) -> None:
"""推入信号样本,超出容量时丢弃最旧的。"""
if len(self._items) >= self._capacity:
self._items.pop(0)
self._items.append(item)
def get_latest(self) -> T | None:
"""获取最新样本。"""
return self._items[-1] if self._items else None
def get_all(self) -> list[T]:
"""获取所有样本。"""
return self._items.copy()
def __len__(self) -> int:
return len(self._items)
# 使用时指定类型参数
int_buffer: SignalBuffer[int] = SignalBuffer(capacity=5)
int_buffer.push(100)
int_buffer.push(200)
int_buffer.push(300)
print(int_buffer.get_latest()) # 300
float_buffer: SignalBuffer[float] = SignalBuffer(capacity=3)
float_buffer.push(3.14)
float_buffer.push(2.71)
print(float_buffer.get_latest()) # 2.71
ParamSpec(Python 3.10+)
ParamSpec(PEP 612)捕获可调用对象的参数签名,常用于装饰器类型注解:
from typing import ParamSpec, TypeVar, Callable
from functools import wraps
import time
P = ParamSpec("P") # 参数签名变量
R = TypeVar("R") # 返回值变量
def timer(func: Callable[P, R]) -> Callable[P, R]:
"""计时装饰器,保留原函数的参数签名。"""
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} 耗时 {elapsed:.6f}s")
return result
return wrapper
@timer
def add(a: int, b: int) -> int:
return a + b
@timer
def greet(name: str, *, greeting: str = "Hello") -> str:
return f"{greeting}, {name}"
print(add(1, 2)) # add 耗时 ... / 3
print(greet("Alice", greeting="Hi")) # greet 耗时 ... / Hi, Alice
没有 ParamSpec,装饰器只能用 Callable[..., R],会丢失原函数的参数信息——类型检查器无法检查 add("a", "b") 这样的错误调用。ParamSpec 让装饰器精确转发参数签名,是编写类型安全的装饰器的关键工具。
TypeGuard:类型守卫
TypeGuard 用于在条件分支中收窄类型(上一节已介绍)。这里展示一个更实用的例子:
from typing import TypeGuard, Any
def is_flight_state(obj: Any) -> TypeGuard[dict[str, object]]:
"""判断 obj 是否为符合飞行状态格式的字典。"""
return (
isinstance(obj, dict)
and "altitude" in obj
and isinstance(obj["altitude"], (int, float))
)
def handle(data: object) -> str:
if is_flight_state(data):
# 这里 data 被收窄为 dict[str, object]
altitude: int | float = data["altitude"] # 类型检查器知道这是数值
return f"当前高度:{altitude}m"
return "非飞行状态数据"
print(handle({"altitude": 1000, "speed": 50})) # 当前高度:1000m
print(handle("hello")) # 非飞行状态数据
Literal:字面量类型
Literal 把值本身作为类型,常用于限定参数取值范围:
from typing import Literal
def set_mode(mode: Literal["r", "w", "a"]) -> str:
return f"以 {mode} 模式打开"
print(set_mode("r")) # 以 r 模式打开
# set_mode("x") # 类型检查器报错:字面量 "x" 不在 Literal["r", "w", "a"] 中
# 布尔字面量
def configure(debug: Literal[True] | None = None) -> None:
if debug:
print("调试模式开启")
configure(True)
configure(None)
# configure(False) # 类型检查器报错
- 限定字符串参数取值(如模式、状态、配置项)
- 标记"重载分支"(配合
@overload) - 与
Enum互补——Literal用于少量固定值,Enum用于大量枚举
Final:不可变绑定
Final 标注"最终"变量——声明后不应重新赋值:
from typing import Final
MAX_CONNECTIONS: Final[int] = 100
TIMEOUT: Final[float] = 30.0
APP_NAME: Final[str] = "MyApp"
# MAX_CONNECTIONS = 200 # 类型检查器报错:Final 变量不应重新赋值
print(f"{APP_NAME}: 最多 {MAX_CONNECTIONS} 连接,超时 {TIMEOUT}s")
Final 也可用于类属性,表示子类不应覆盖:
class Config:
VERSION: Final[str] = "1.0.0"
MAX_RETRIES: Final[int] = 3
class SubConfig(Config):
pass
# VERSION = "2.0.0" # 类型检查器报错:不应覆盖 Final 属性
Final 是类型检查期的"常量"声明,运行时不强制。它告诉类型检查器"这个变量不应被重新赋值",便于发现意外修改。与 const(其他语言)不同,Python 的 Final 只约束重新绑定,不约束对象内容——Final 的列表仍可 append。
ClassVar:类变量
ClassVar 标注"类变量"——属于类而非实例,不应在实例上设置:
from typing import ClassVar
class Counter:
# 类变量:所有实例共享
total_created: ClassVar[int] = 0
instances: ClassVar[list["Counter"]] = []
def __init__(self, name: str) -> None:
self.name = name # 实例变量
Counter.total_created += 1
Counter.instances.append(self)
c1 = Counter("first")
c2 = Counter("second")
print(Counter.total_created) # 2
print([c.name for c in Counter.instances]) # ['first', 'second']
# 类型检查器会警告:不应在实例上设置 ClassVar
# c1.total_created = 100 # 不推荐
Protocol:结构化类型
Protocol(PEP 544)定义结构化类型——鸭子类型的类型化版本。只要对象有相应的方法/属性,就算"实现"了协议,无需继承:
from typing import Protocol
class SupportsClose(Protocol):
"""有 close() 方法的对象。"""
def close(self) -> None: ...
def cleanup(resource: SupportsClose) -> None:
resource.close()
class FileLike:
"""无需继承 SupportsClose,只要有 close 方法即可。"""
def close(self) -> None:
print("文件已关闭")
class Connection:
def close(self) -> None:
print("连接已关闭")
cleanup(FileLike()) # 文件已关闭
cleanup(Connection()) # 连接已关闭
Protocol 与 ABC(抽象基类)都用于定义接口,但机制不同:
- ABC:nominal typing,必须显式继承才算是子类
- Protocol:structural typing,只要结构匹配就算实现
Protocol 更灵活,特别适合"第三方类适配"——我们可以为已有类"声明"协议而无需修改其源码。
带属性的 Protocol
from typing import Protocol
class Identifiable(Protocol):
"""有 sensor_id 属性的对象。"""
sensor_id: str
def register_sensor(sensor: Identifiable) -> str:
return f"注册传感器:{sensor.sensor_id}"
class TemperatureSensor:
def __init__(self, sensor_id: str) -> None:
self.sensor_id = sensor_id
class PressureSensor:
sensor_id: str = "PS-001"
print(register_sensor(TemperatureSensor("TS-100"))) # 注册传感器:TS-100
print(register_sensor(PressureSensor())) # 注册传感器:PS-001
运行时检查 Protocol
默认情况下 Protocol 只用于静态检查。加 @runtime_checkable 装饰器后,可以用 isinstance 检查:
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("画圆")
class Square:
def draw(self) -> None:
print("画方")
print(isinstance(Circle(), Drawable)) # True
print(isinstance(Square(), Drawable)) # True
print(isinstance("hello", Drawable)) # False
@runtime_checkable 的 isinstance 检查只验证方法/属性存在,不验证签名。它只能检查属性名是否存在,无法检查参数类型或返回类型。复杂协议的运行时检查可能不可靠。
TypedDict:类型化字典
TypedDict(PEP 589)给字典的每个键标注类型,弥补"普通 dict 类型太宽泛"的问题:
from typing import TypedDict
class SensorReading(TypedDict):
sensor_id: str
timestamp: float
value: float
unit: str
# 字典字面量会被检查器按 SensorReading 结构校验
reading: SensorReading = {
"sensor_id": "TS-100",
"timestamp": 1703980800.0,
"value": 25.5,
"unit": "°C",
}
print(reading["value"]) # 25.5
# reading["value"] = "abc" # 类型检查器报错:应为 float
可选键与 required/NotRequired
from typing import TypedDict, NotRequired
class FlightEvent(TypedDict):
event_type: str
timestamp: float
details: str
altitude: NotRequired[float] # 可选键
event: FlightEvent = {"event_type": "takeoff", "timestamp": 1703980800.0, "details": "起飞"} # 不写 altitude 也合法
print(event)
Python 3.11+ 引入了 Required 和 NotRequired:
- 默认所有键都是必需的
NotRequired[X]标记可选键- 也可用
total=False让整个 TypedDict 的所有键都可选
class FilterConfig(TypedDict, total=False):
"""所有键都可选。"""
cutoff_freq: float
sample_rate: int
order: int
函数式写法
TypedDict 也可用函数式语法创建:
from typing import TypedDict
SensorData = TypedDict("SensorData", {"x": float, "y": float, "label": str})
p: SensorData = {"x": 1.0, "y": 2.0, "label": "gyro"}
print(p)
Annotated:附加元信息
Annotated[X, meta] 在类型之外附加额外元信息,常用于校验、文档、序列化框架:
from typing import Annotated
from dataclasses import dataclass
# 附加验证信息(需要框架支持,如 pydantic)
def validate_positive(x: float) -> bool:
return x > 0
@dataclass
class SignalConfig:
name: str
sample_rate: Annotated[int, "采样率必须为正整数", validate_positive] = 1000
duration: Annotated[float, "持续时间 0-3600s"] = 1.0
s = SignalConfig("gyro_x", 1000, 0.5)
print(s)
print(SignalConfig.__annotations__)
# {'name': <class 'str'>, 'sample_rate': typing.Annotated[int, '采样率必须为正整数', ...], ...}
# 运行时访问附加信息
from typing import get_type_hints
hints = get_type_hints(SignalConfig, include_extras=True)
print(hints["sample_rate"].__metadata__) # ('采样率必须为正整数', <function validate_positive>)
Annotated 让类型注解携带额外数据,被各类框架利用:
- Pydantic:
Annotated[int, Field(gt=0)]表达"正整数" - FastAPI:
Annotated[str, Query(max_length=50)]表达"URL 查询参数" - cattrs:自定义反序列化逻辑
运行时通过 typing.get_type_hints(cls, include_extras=True) 读取附加的元信息。
Python 3.12+ 新特性
type 语句定义泛型
Python 3.12 的 type 语句(PEP 695)支持泛型参数,无需 TypeVar:
# 旧写法
from typing import TypeVar, Generic
T_old = TypeVar("T_old")
class Buffer_old(Generic[T_old]):
def __init__(self) -> None:
self._items: list[T_old] = []
# Python 3.12+ 新写法:泛型类直接用 [T]
class Buffer[T]:
"""泛型缓冲区,无需 TypeVar 和 Generic。"""
def __init__(self) -> None:
self._items: list[T] = []
def push(self, item: T) -> None:
self._items.append(item)
def pop(self) -> T:
return self._items.pop()
s = Buffer[int]()
s.push(1)
print(s.pop()) # 1
# 泛型函数也支持
def first[T](items: list[T]) -> T | None:
return items[0] if items else None
print(first([1, 2, 3])) # 1
# 泛型类型别名
type Pair[T] = tuple[T, T]
p: Pair[str] = ("hello", "world")
print(p)
Python 3.12(PEP 695)引入的 type 语句和泛型类语法,让 Python 的泛型表达接近 Rust/Haskell 的简洁程度。关键变化:
- 泛型类:
class Stack[T]:直接声明类型参数 - 泛型函数:
def first[T](items: list[T]):直接声明 - 泛型类型别名:
type Pair[T] = tuple[T, T]
这些新语法无需导入 TypeVar 和 Generic,更简洁直观。
实战:信号处理协议
下面实现一个类型安全的信号处理系统,综合运用 Generic、TypeVar、Protocol、Literal 等工具:
from __future__ import annotations
from typing import Protocol, TypeVar, Generic, Literal, overload
from dataclasses import dataclass, field
import numpy as np
class FlightState(Protocol):
"""可比较的飞行状态(支持 < 运算)。"""
altitude: float
speed: float
def __lt__(self, other: object) -> bool: ...
@dataclass(order=True)
class DroneState:
"""无人机飞行状态。"""
altitude: float
speed: float
battery: float = 100.0
def __lt__(self, other: object) -> bool:
if not isinstance(other, DroneState):
return NotImplemented
return self.altitude < other.altitude
T = TypeVar("T", bound=FlightState)
@dataclass
class StateBuffer(Generic[T]):
"""按高度排序的飞行状态缓冲区。"""
_items: list[T] = field(default_factory=list)
order: Literal["asc", "desc"] = "asc"
def add(self, item: T) -> None:
"""插入并保持有序。"""
pos = 0
if self.order == "asc":
while pos < len(self._items) and self._items[pos] < item:
pos += 1
else:
# 降序:找到第一个不小于 item 的位置
while pos < len(self._items) and item < self._items[pos]:
pos += 1
self._items.insert(pos, item)
@overload
def get(self, index: int) -> T: ...
@overload
def get(self, index: slice) -> list[T]: ...
def get(self, index: int | slice) -> T | list[T]:
"""按索引获取元素。"""
return self._items[index]
def __len__(self) -> int:
return len(self._items)
def __iter__(self):
return iter(self._items)
def __repr__(self) -> str:
return f"StateBuffer({self._items!r}, order={self.order!r})"
# 使用:按高度升序排列
asc_buffer: StateBuffer[DroneState] = StateBuffer(order="asc")
asc_buffer.add(DroneState(altitude=500, speed=20))
asc_buffer.add(DroneState(altitude=100, speed=15))
asc_buffer.add(DroneState(altitude=300, speed=25))
print(asc_buffer) # StateBuffer([DroneState(altitude=100, ...), ...], order='asc')
print(asc_buffer.get(0)) # DroneState(altitude=100, speed=15, battery=100.0)
print(asc_buffer.get(1:3)) # [DroneState(altitude=300, ...), DroneState(altitude=500, ...)]
# 使用:按高度降序排列
desc_buffer: StateBuffer[DroneState] = StateBuffer(order="desc")
for s in asc_buffer:
desc_buffer.add(s)
print(list(desc_buffer))
# [DroneState(altitude=500, ...), DroneState(altitude=300, ...), DroneState(altitude=100, ...)]
@overload 装饰器用于声明多个类型签名,帮助类型检查器理解函数在不同参数下的不同返回类型。实际运行的是最后一个未带 @overload 的实现。上例中 get(0) 返回 T,get(1:3) 返回 list[T]——这种"参数类型决定返回类型"的场景正是 @overload 的用武之地。
🎯 动手练习
- 泛型容器:实现一个泛型信号缓冲区
SignalBuffer[T],支持push、pop、peek操作 - Protocol 设计:用
Protocol定义一个可序列化接口,让多个类实现它 - TypedDict 配置:用
TypedDict定义应用配置类型,支持可选字段 - 装饰器类型:用
ParamSpec和TypeVar为一个日志装饰器添加完整类型注解
Any任意类型def f(x: Any) -> Any:object所有类型基类def f(x: object):NoReturn永不返回def abort() -> NoReturn:Never空类型(3.11+)def abort() -> Never:Callable可调用对象Callable[[int, str], bool]TypeVar类型变量T = TypeVar("T")Generic泛型基类class Box(Generic[T]):ParamSpec参数签名(3.10+)P = ParamSpec("P")Literal字面量类型Literal["GET", "POST"]Final不可变绑定MAX_SIZE: Final = 100ClassVar类变量count: ClassVar[int] = 0Protocol结构化类型class Serializable(Protocol):TypedDict类型化字典class Config(TypedDict):Annotated附加元信息Annotated[int, Gt(0)]TypeGuard类型守卫(3.10+)def is_str(x) -> TypeGuard[str]:📚 延伸阅读
- typing 官方文档 - 完整 API 参考
- PEP 484 - 类型提示规范
- PEP 544 - Protocol 规范
- PEP 589 - TypedDict 规范
- PEP 612 - ParamSpec 规范
- PEP 695 - Python 3.12 泛型语法
✅ 本节总结
Any放弃类型检查,应优先用object;NoReturn/Never标注永不返回的函数Callable[[参数], 返回]标注可调用对象;Callable[..., R]表示任意参数Iterable/Iterator/Generator标注迭代相关类型TypeVar定义类型变量,Generic定义泛型类;bound限定子类,受限TypeVar限定取值ParamSpec(3.10+)捕获参数签名,是装饰器类型注解的关键Literal表达字面量类型;Final标注不可变绑定;ClassVar标注类变量Protocol定义结构化类型(鸭子类型的类型化);TypedDict类型化字典Annotated在类型之外附加元信息,被 Pydantic/FastAPI 等框架利用- Python 3.12+ 的
type语句和泛型类语法(PEP 695)让泛型表达更简洁
下一节将学习异步编程——async/await、asyncio、协程与 TaskGroup。