Python 3.9起可用|替代Union仅限类型注解上下文,如函数参数、返回值、变量声明等,等价于Union[int, str],但不可用于isinstance等运行时检查,且嵌套需括号。

Python 3.9 中 | 运算符可以直接替代 Union
可以,但仅限于类型注解上下文(如变量、函数参数、返回值),且要求所有操作数都是有效类型。Python 3.9 引入了 PEP 604,允许用 | 作为联合类型的语法糖,比如 int | str 等价于 Union[int, str]。
注意:这不改变运行时行为,只影响静态类型检查器(如 mypy、pylance)的解析方式。
-
|只在类型注解中合法;写在运行时表达式里会报TypeError: unsupported operand type(s) - 嵌套联合必须加括号,例如
int | (str | float),否则解析顺序可能出错(|是左结合,但类型系统不按此推导) - 不能混用
Union和|在同一注解中直接拼接,如Union[int, str] | float是无效语法 - 空联合(
Union[()])没有对应|写法,必须继续用Union[()]或改用Never(Python 3.11+)
哪些地方能用 |,哪些不能
能用的地方包括函数签名、变量声明、类属性注解、泛型参数中的类型实参(如 Optional[str] 已被 str | None 替代):
def parse_value(x: int | str | None) -> float | ValueError:
...
data: list[int | str] = [1, "hello"]
不能用的地方:
立即学习“Python免费学习笔记(深入)”;
- 作为
isinstance()或issubclass()的第二个参数(它们仍需Union或具体类型,不支持|) - 传给
typing.get_origin()或get_args()时,需先用typing.get_origin()判断是否为联合类型,因为int | str的__origin__是types.UnionType(Python 3.10+),而Union[int, str]的__origin__是Union - 旧版 typing 模块(如 Python |,会导致
SyntaxError
和 Union 混用或迁移时的兼容性陷阱
如果你在维护跨版本代码(比如同时支持 3.8 和 3.9+),不要直接替换所有 Union —— 因为 | 在 3.8 下非法。更稳妥的做法是:
- 保留
from typing import Union,继续用Union注解,它在 3.9+ 依然完全有效 - 若坚持用
|,需确保项目最低 Python 版本为 3.9,并在pyproject.toml中明确指定requires-python = ">=3.9" - mypy 默认支持
|,但旧版(--python-version 3.9 才能识别;VS Code + Pylance 通常自动适配 -
None在联合中必须显式写出:str | None,不能省略为str |(语法错误)
实际开发中建议怎么选
新项目、明确锁定 Python 3.9+ 的场景,优先用 |:更简洁、可读性高、符合 PEP 604 原意。但要注意工具链是否跟得上。
老项目升级或需兼容旧环境时,Union 更稳——尤其涉及动态构造类型(如 Union[*tuple_of_types])或反射操作时,| 无法替代。
最容易被忽略的一点:int | str 和 Union[int, str] 在运行时不是等价对象,type(int | str) 是 types.UnionType(3.10+),而 Union[int, str] 是 typing.Union 类型对象。做类型元编程时,这点差异会直接影响逻辑分支。


















