解决 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] = None
Python 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 版本间兼容的类型注解代码。