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 原生泛型语法
posted @ 2026-04-23 00:42  悠哉大斌  阅读(31)  评论(0)    收藏  举报