解决 Python 中的 TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'
问题描述
当在 Python 3.9 中尝试使用联合类型语法 |(例如 str | None)时,会遇到以下错误:
python
TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'这个报错出现在如下的类定义中:
python
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""库存物品追踪类"""
name: str | None = None # ❌ 在 Python 3.9 中会引发错误
unit_price: float
quantity_on_hand: int = 0错误原因
报错的根本原因在于:
|语法用于联合类型 (Union Types) 是 Python 3.10 才引入的新特性- Python 3.9 及更低版本不具备理解
type1 | type2的能力 NoneType是特殊类型,不支持与常规类型直接进行|运算
解决方案
方法 1:使用 typing.Optional (首选方案)
typing.Optional 是表示"某种类型或 None"的标准解决方案,兼容 Python 3.5+。
python
from typing import Optional
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""库存物品追踪类"""
name: Optional[str] = None # ✅ Python 3.9 中安全的方式
unit_price: float
quantity_on_hand: int = 0重要提示
确保数据类中 字段顺序正确:没有默认值的字段必须声明在带有默认值的字段前面。
方法 2:使用 typing.Union (多类型场景)
当需要联合多于两种类型时,使用 typing.Union:
python
from typing import Union
# 接受 str, int, float 三种类型
value: Union[str, int, float] = 42
# 接受 str 或 None 类型
text: Union[str, None] = NonePython 3.10+ 的正确写法
如果环境升级到 Python 3.10+,可以恢复使用简化的 | 语法:
python
@dataclass
class InventoryItem:
"""库存物品追踪类"""
name: str | None = None # ✅ Python 3.10+ 中安全可用
unit_price: float
quantity_on_hand: int = 0注意事项
Optional[str]和Union[str, None]在功能上完全等价Optional[...]更简洁,是表示可空值的惯用写法- 避免尝试用
or替代,如str or None,这会导致不同语义的错误
完整修正代码
综合考虑字段顺序和类型注解兼容性的最终方案:
python
from typing import Optional
from dataclasses import dataclass
@dataclass
class InventoryItem:
"""库存物品追踪类"""
unit_price: float # 🚫 无默认值字段在前
name: Optional[str] = None # ✅ 使用 Optional 声明可空类型
quantity_on_hand: int = 0 # 有默认值字段在后关键点总结
| 问题场景 | Python 3.9 解决方案 | Python 3.10+ 解决方案 |
|---|---|---|
str 或 None | Optional[str] | str | None |
| 多种类型联合 | Union[Type1, Type2, ...] | Type1 | Type2 | ... |
| 类字段顺序问题 | 无默认值的字段必须在前面 | 无默认值的字段必须在前面 |
遇到类似的 TypeError 时,首先检查 Python 版本,并根据运行环境选择恰当的联合类型语法。遵循这些注意事项将帮助你避免这种类型错误,并能写出在不同 Python 版本间兼容的类型注解代码。