Python 3.12 通过 PEP 695 引入了更强大的高级类型参数机制,包括 可变类型参数(*Ts) 和 参数规格(**P),用于处理复杂泛型场景(如可变参数函数、回调函数类型等)。以下是对它们的详细解析:
1. 可变类型参数(*Ts)#
用途#
表示一组不定数量的类型参数,类似 *args 的泛型版本。常用于:
- 泛型元组或可变长度容器
- 函数参数的类型标注(如
*args: *Ts)
语法与示例#
</>
python
1from typing import Tuple
2
3# 定义泛型元组,第一个元素为 str,其余元素类型可变
4type LabeledTuple[*Ts] = tuple[str, *Ts] # PEP 695 语法
5
6# 使用
7x: LabeledTuple[int, float] = ("id", 42, 3.14) # 等效于 tuple[str, int, float]
8y: LabeledTuple[bool] = ("flag", True) # 等效于 tuple[str, bool]
9
10# 函数中的可变参数类型
11def zip[*T](*args: *T) -> list[tuple[*T]]: # 模拟内置 zip 的类型
12 return list(zip(*args))关键点#
*Ts表示类型元组,可匹配任意数量的类型参数。- 运行时会被擦除为
tuple,仅静态类型检查器(如 mypy)会验证类型安全性。 - 与传统
TypeVarTuple等效(Python 3.11 之前需用from typing import TypeVarTuple)。
2. 参数规格(**P)#
用途#
描述函数的参数类型和返回值类型,用于泛型高阶函数(如装饰器、回调函数)。类似 **kwargs 的泛型扩展。
语法与示例#
</>
python
1from typing import Callable
2
3# 定义泛型回调函数类型:参数类型为 **P,返回值为 int
4type IntFunc[**P] = Callable[P, int] # PEP 695 语法
5
6# 使用
7def foo(x: str, y: float) -> int:
8 return len(x) + int(y)
9
10f: IntFunc[str, float] = foo # 匹配参数 (str, float) -> int
11
12# 泛型装饰器
13def logger[**P, R](func: Callable[P, R]) -> Callable[P, R]:
14 def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
15 print(f"Calling {func.__name__}")
16 return func(*args, **kwargs)
17 return wrapper关键点#
**P表示参数规格(Parameter Specification),捕获函数的参数类型(位置参数和关键字参数)。- 与传统 ParamSpec
等效(Python 3.11 之前需用
from typing import ParamSpec)。 - 结合
P.args和P.kwargs可精确描述函数签名。
3. 高级组合用法#
(1) 泛型可变参数函数#
</>
python
1def call_with_args[*Ts, R](func: Callable[[*Ts], R], *args: *Ts) -> R:
2 return func(*args)
3
4# 使用
5def add(a: int, b: int) -> int:
6 return a + b
7
8call_with_args(add, 1, 2) # Ts 推断为 (int, int), R 为 int(2) 泛型装饰器工厂#
</>
python
1type Decorator[**P, R] = Callable[[Callable[P, R]], Callable[P, R]]
2
3def retry[**P, R](max_attempts: int) -> Decorator[P, R]:
4 def decorator(func: Callable[P, R]) -> Callable[P, R]:
5 def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
6 for _ in range(max_attempts):
7 try:
8 return func(*args, **kwargs)
9 except Exception:
10 continue
11 raise RuntimeError("All attempts failed")
12 return wrapper
13 return decorator
14
15@retry(max_attempts=3)
16def fetch_data(url: str) -> dict:
17 import requests
18 return requests.get(url).json()4. 与传统语法的对比#
| 特性 | Python 3.12 新语法 | 旧语法(3.11 及之前) |
|---|---|---|
| 可变类型参数 | type Tuple[*Ts] = ... | Ts = TypeVarTuple("Ts") |
| 参数规格 | type Func[**P] = ... | P = ParamSpec("P") |
| 类型约束 | [*Ts: (int, str)] | Ts = TypeVarTuple("Ts", int, str) |
5. 注意事项#
- 静态类型检查依赖:
- 需使用支持 PEP 695 的工具链(如 mypy 1.11+、pyright)。
- 运行时无类型信息(类型擦除)。
- 性能影响:
- 泛型类型注解不影响运行时性能,但复杂嵌套可能增加静态检查时间。
- 兼容性:
- 旧代码可逐步迁移,新旧语法混用需确保类型检查器兼容。
总结#
Python 3.12 的 *Ts 和 **P 提供了更直观的泛型抽象能力:
*Ts:用于可变长度类型序列(如元组、*args)。**P:用于精确描述函数参数类型(如装饰器、回调)。- 设计目标:减少
typing模块的样板代码,提升代码可读性,同时保持与静态类型检查器的深度集成。