引入Pydantic后标准库frozen+slots数据类报只读属性错误原因?
标准库数据类结合Pydantic后初始化报错问题
首先看一段可正常运行的标准库数据类代码:
from dataclasses import dataclass @dataclass(slots=True, frozen=True) class MyStdLibDataclass: x : int = 0 d1 = MyStdLibDataclass(x=100) assert d1.x == 100
但在同一文件中添加Pydantic相关代码后:
from pydantic import BaseModel class MyModel(BaseModel): y : MyStdLibDataclass|None = None d2 = MyStdLibDataclass(x=101) # 此处报错 assert d2.x == 101
会触发以下错误:
Traceback (most recent call last): File "C:\Users\Ross\Desktop\dataclass_bug.py", line 15, in <module> d2 = MyStdLibDataclass(x=101) File "<string>", line 3, in __init__ AttributeError: 'MyStdLibDataclass' object attribute 'x' is read-only
问题原因
Pydantic 2.x在处理标准库数据类时,会对数据类进行运行时动态增强,添加验证相关逻辑。但对于同时设置了slots=True和frozen=True的数据类,这个增强过程会干扰原有的初始化逻辑,导致第一次赋值时错误地判定字段为只读状态。
Pydantic并没有修改标准库数据类的核心实现,但动态增强的过程和frozen=True+slots=True的组合存在兼容性冲突。
解决方案
有几种可行的解决方式:
- 调整数据类参数:移除
slots=True或frozen=True中的一个。比如只保留只读特性:
@dataclass(frozen=True) class MyStdLibDataclass: x : int = 0
或只保留内存优化的slots特性:
@dataclass(slots=True) class MyStdLibDataclass: x : int = 0
- 使用Pydantic数据类替代标准库版本:Pydantic的
dataclass原生支持slots=True和frozen=True的组合,不会出现兼容问题:
from pydantic.dataclasses import dataclass @dataclass(slots=True, frozen=True) class MyStdLibDataclass: x : int = 0
- 阻止Pydantic增强标准库数据类:通过
Annotated搭配PlainSerializer,让Pydantic直接使用原始数据类,不做额外修改:
from pydantic import BaseModel, PlainSerializer from typing import Annotated class MyModel(BaseModel): y: Annotated[MyStdLibDataclass|None, PlainSerializer(lambda x: x)] = None
内容的提问来源于stack exchange,提问作者Ross Bencina
相关产品推荐
相关产品推荐

