Python 泛型演变史
Python 泛型(Generics)的演变几乎就是 Python 类型系统演变的主线。
甚至可以说:
类型提示的发展 = 泛型能力不断增强。
它大概经历了五代。
Python 泛型演变史
一、没有泛型的时代
最早只能写:
def first(items):
return items[0]
问题:
- 输入元素类型丢失
- 返回类型无法关联输入
比如:
first([1,2,3]) # 应该推断 int
早期做不到。
二、PEP 484:TypeVar 时代(第一代泛型)
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)
只允许:
- 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:内置泛型时代
PEP 585
旧:
List[T]
新:
list[T]
这件事意义比看起来大。
因为:
list
自己变成 generic class。
这很像:
List<T>
只是 Python 化。
嵌套泛型更舒服
dict[str, list[int]]
自定义泛型仍旧笨重
问题还在:
class Box(Generic[T]):
还是冗长。
所以还有下一步。
四、高阶泛型时代
这是高手区。
ParamSpec
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]:
...
参数原封保留。
这是二阶泛型。
TypeVarTuple
更疯狂。
Ts = TypeVarTuple("Ts")
可变长度泛型:
tuple[*Ts]
比如:
tuple[int, str, float]
都能表达。
像 C++ variadic templates。
五、PEP 695:新泛型语法(革命)
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]:
终于不需要:
- Generic
- TypeVar
泛型别名
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。
例如:
- Literal
- TypeGuard
- Variadic generics
越来越像现代类型系统。
一个很有趣的暗线
Python 泛型其实在逐渐摆脱 Java 风格。
早期:
很像 Java:
class Box<T>
后来越来越像 TypeScript / Rust:
type Result[T] = T | Error
风格变了。
对照图
| 年代 | 泛型能力 |
|---|---|
| pre-484 | 无 |
| PEP 484 | TypeVar |
| PEP 585 | 内置泛型 |
| ParamSpec时代 | 高阶泛型 |
| PEP 695 | 原生泛型语法 |
浙公网安备 33010602011771号