python 3.10+ 的 | 是原生联合类型运算符,仅在类型注解中合法,运行时不可用于 isinstance 或反射;union 已弃用但仍是动态操作的唯一选择。

| 是 Python 3.10+ 类型系统原生支持的运算符(PEP 604),不是语法糖,它直接参与 AST 解析,生成 types.UnionType 实例;而 Union 已被标记为弃用,类型检查器(如 mypy 0.950+、pyright)默认报 warning 或 error。
运行时不能用 | 做类型判断
写 isinstance(x, int | str) 会直接抛 TypeError: isinstance() arg 2 must be a type or tuple of types。因为 | 在运行时不产生可被 isinstance 接受的元组或类型对象。
- 正确写法只能是
isinstance(x, (int, str)) - 若需动态构造联合类型用于反射(如读取
Union.__args__),必须用from typing import Union,不能用| -
type_union = int | str后再传给函数做类型操作,大概率触发AttributeError或TypeError
| 只在类型标注上下文中合法
它只在函数签名、变量注解、类属性等 AST 类型注解位置有效,其他地方用就错。
- ✅ 允许:
def f(x: str | bytes) -> dict[str, int] | None: - ❌ 禁止:
if x is None or isinstance(x, str | bytes): - ⚠️ 危险:
alias = str | int然后试图getattr(alias, '__args__')——types.UnionType没有__args__属性
mypy/pyright 对 Union 和 | 的处理差异
工具链对二者底层表示不同,导致行为不一致:
- mypy 默认把
str | int视为等价于Union[str, int],但会拒绝Union[str, None]并提示 “Use 'str | None' instead” - pyright 在某些泛型嵌套场景(如
List[str | int])可能报错,而List[Union[str, int]]反而通过 - IDE 补全依赖 Python 版本配置:PyCharm/Pylance 若未识别项目为 3.10+,输完
int |后不提示后续类型 -
get_type_hints()返回结果中,|形式可能被标准化为Union对象,具体取决于是否启用from __future__ import annotations和 Python 版本
嵌套复杂时别硬套 |
简单联合(如 int | str | None)用 | 更清晰;但嵌套过深时,括号和缩进极易出错,反而降低可维护性。
- 难读示例:
list[dict[str, int | float | None]] | tuple[str, ...] | None - 推荐改用
Union并分行书写:Union[ list[dict[str, Union[int, float, None]]], tuple[str, ...], None ] - 团队统一风格很重要:混用
Optional[str]和str | None会导致 mypy 报inconsistent-union
| 的合法性仅存在于 AST 解析阶段,它不参与运行时逻辑;一旦你把它当普通表达式用(比如赋值、传参、反射),就会触发运行时错误——这不是配置问题,是语言设计本身决定的。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











