Python 类型别名的演变

类型别名(Type Alias)在 Python typing 演进里是条很有意思的支线,因为它经历了 隐式别名 → 显式别名 → 新语法别名 三个阶段。


Python 类型别名的演变

1 最早:隐式类型别名(PEP 484时代)

最初根本没有专门语法。

只要把类型赋值给变量,就是别名:

Vector = list[float]

然后:

def magnitude(v: Vector) -> float:
    ...

Vector 只是:

list[float]

的名字。


为什么需要别名

否则复杂类型会变成噩梦:

dict[str, list[tuple[int, str | None]]]

改成:

UserMap = dict[str, list[tuple[int, str | None]]]

可读性高很多。


JSON 类型经典例子

JSON = (
    dict[str, "JSON"]
    | list["JSON"]
    | str
    | int
    | float
    | bool
    | None
)

这个几乎是教科书案例。


2 问题:变量还是别名?

麻烦在于:

Config = dict[str, str]

这是:

  • 类型别名?

还是:

  • 一个变量值?

静态检查器要猜。

很不优雅。


3 PEP 613:TypeAlias(显式声明)

PEP 613

Python 3.10:

from typing import TypeAlias

Vector: TypeAlias = list[float]

现在明确告诉类型检查器:

这是 alias,不是变量。


好处一:消除歧义

以前:

MyType = "ClassName"

是字符串变量?

还是前向引用别名?

不清楚。

现在:

MyType: TypeAlias = "ClassName"

明确。


好处二:泛型别名

from typing import TypeVar, TypeAlias

T = TypeVar("T")

Vec: TypeAlias = list[T]

很漂亮。


好处三:类型检查更好

mypy / Pyright 能报更准确错误。

比如:

Alias: TypeAlias = 42

会报错。

因为不是合法类型。


4 PEP 695:新一代 type 语句(Python 3.12)

大升级。

PEP 695

现在:

type Vector = list[float]

不是赋值。

是真正类型声明。

像:

  • TypeScript
type Vector = number[]
  • Rust
type Vector = Vec<f64>;

Python 第一次有正式 type statement。


泛型别名更优雅

旧:

T = TypeVar("T")
Vec = list[T]

新:

type Vec[T] = list[T]

这个非常漂亮。


条件类型组合也更舒服

type Response[T] = T | Exception

递归别名

以前很痛苦:

JSON = dict[str, JSON] | ...

新语法支持更自然。


5 TypeAlias vs NewType(常被混淆)

这个必须讲。

TypeAlias

只是换名字:

type UserId = int

本质:

UserId is int

没区别。


NewType

NewType

from typing import NewType

UserId = NewType("UserId", int)

这是静态层面新类型:

user: UserId

不能随便拿 ProductId 混进来。


举例

坏:

type UserId = int
type ProductId = int

类型检查器认为一样。


好:

UserId = NewType("UserId", int)
ProductId = NewType("ProductId", int)

不会混。

这很适合领域建模。


6 三代演化总结

阶段 写法
PEP 484 Vector = list[float]
PEP 613 Vector: TypeAlias = list[float]
PEP 695 type Vector = list[float]

很明显是:

从约定
到显式标注
到语言语法


强调一点

类型别名不是“缩写”。

它本质是:

  • 可读性工具
  • 抽象边界
  • 领域建模工具

比如:

type Money = Decimal
type Email = str
type UserRecord = dict[str, str | int]

这已经有 DSL 味道了。

posted @ 2026-04-23 00:33  悠哉大斌  阅读(34)  评论(0)    收藏  举报