




















Python 泛型(Generics)的演变几乎就是 Python 类型系统演变的主线。
甚至可以说:
类型提示的发展 = 泛型能力不断增强。
它大概经历了五代。
最早只能写:
def first(items):
return items[0]
问题:
比如:
first([1,2,3]) # 应该推断 int
早期做不到。
PEP 484
这是经典写法:
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T:
return items[0]
现在:
输入是 list[int]
返回自动是:
int
其实就是:
f : T -> T
identity function。
def identity(x: T) -> T:
return x
非常经典。
T = TypeVar("T", int, float)
只允许:
T = TypeVar("T", bound=str)
必须是 str 子类。
from typing import Generic
T = TypeVar("T")
class Box(Generic[T]):
def __init__(self, value: T):
self.value = value
使用:
Box[int]
这是 Python 泛型正式诞生。
PEP 585
旧:
List[T]
新:
list[T]
这件事意义比看起来大。
因为:
list
自己变成 generic class。
这很像:
List<T>
只是 Python 化。
dict[str, list[int]]
问题还在:
class Box(Generic[T]):
还是冗长。
所以还有下一步。
这是高手区。
ParamSpec
普通 TypeVar 只能描述值类型。
描述不了:
函数参数列表。
装饰器以前很难写:
def log(fn):
...
会丢签名。
有 ParamSpec:
from typing import ParamSpec
from collections.abc import Callable
P = ParamSpec("P")
T = TypeVar("T")
def log(fn: Callable[P, T]) -> Callable[P, T]:
...
参数原封保留。
这是二阶泛型。
更疯狂。
Ts = TypeVarTuple("Ts")
可变长度泛型:
tuple[*Ts]
比如:
tuple[int, str, float]
都能表达。
像 C++ variadic templates。
PEP 695
这是最大飞跃。
旧:
T = TypeVar("T")
def identity(x: T) -> T:
新:
def identity[T](x: T) -> T:
像 TypeScript:
function identity<T>(x:T): T
旧:
class Box(Generic[T]):
新:
class Box[T]:
终于不需要:
type Vec[T] = list[T]
漂亮得不像 Python。
def add[T: (int, float)](x:T, y:T) -> T:
约束直接放签名。
“类型参数存在了”
TypeVar
“标准库类型成为泛型”
list[T]
“高阶泛型”
ParamSpec
TypeVarTuple
“语法内建泛型”
def foo[T]()
开始有点像轻量 dependent typing。
例如:
越来越像现代类型系统。
Python 泛型其实在逐渐摆脱 Java 风格。
早期:
很像 Java:
class Box<T>
后来越来越像 TypeScript / Rust:
type Result[T] = T | Error
风格变了。
| 年代 | 泛型能力 |
|---|---|
| pre-484 | 无 |
| PEP 484 | TypeVar |
| PEP 585 | 内置泛型 |
| ParamSpec时代 | 高阶泛型 |
| PEP 695 | 原生泛型语法 |
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。