You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pydantic类字段标注为父类时反序列化错误解决方案

Pydantic多态模型序列化反序列化类型丢失修复

问题表现

对包含父类类型字段、实际传入子类实例的Pydantic模型做dict()序列化后,再反序列化回原模型类时,子类独有的字段会丢失,字段被解析为父类实例,反序列化结果与原实例不相等,触发断言错误。

复现代码

from typing import Tuple, List
from pydantic import BaseModel

class A(BaseModel):
    a: int

class B(A):
    b: float

class C(BaseModel):
    data: A

b = B(a=1, b=0.2)
c = C(data=b)
c_again = C(**c.dict())
print(c, ", ", c_again)
assert c == c_again

运行报错输出

data=B(a=1, b=0.2) ,  data=A(a=1)
Traceback (most recent call last):
  File "/home/h-ishida/tmp/tmp.py", line 18, in <module>
    assert c == c_again
AssertionError

问题根因

默认序列化逻辑不会在字典结果中保留实例的实际子类类型标识,反序列化阶段Pydantic只会按照字段声明的父类A的字段结构做校验解析,子类独有的b字段会被直接忽略,最终生成父类A的实例,和原B实例不一致。

修复方案

推荐使用显式类型判别字段实现多态解析,兼容性最好,不会出现隐式匹配错误,Pydantic v1/v2 均支持:

  • 给父类和所有子类添加固定的类型标识字段,用Literal限定每个类对应的标识值
  • 引用多态类型的字段,声明为所有子类+父类的联合类型,通过discriminator参数指定类型判别字段
  • 序列化时会自动将类型标识写入字典,反序列化时Pydantic会根据标识值自动匹配对应子类实例

修复后可运行代码

from typing import Literal, Union
from pydantic import BaseModel, Field

class A(BaseModel):
    # 父类类型标识
    type: Literal["a"] = "a"
    a: int

class B(A):
    # 子类类型标识,固定值为"b"
    type: Literal["b"] = "b"
    b: float

class C(BaseModel):
    # 声明为联合类型,指定按type字段判别具体类型
    data: Union[A, B] = Field(discriminator="type")

b = B(a=1, b=0.2)
c = C(data=b)
# Pydantic v2 写法
c_dict = c.model_dump()
c_again = C.model_validate(c_dict)
# Pydantic v1 把上面两行替换为下面两行即可
# c_dict = c.dict()
# c_again = C.parse_obj(c_dict)
print(c, ", ", c_again)
assert c == c_again

运行后输出为data=B(a=1, b=0.2) , data=B(a=1, b=0.2),断言正常通过。

如果不想新增显式的类型字段,且子类数量少、字段结构无重叠,也可以直接将字段声明为Union[B, A](注意子类要写在父类前面),Pydantic会优先按照子类结构匹配字典,匹配成功则生成子类实例,但这种方式存在字段重叠时匹配错误的风险,不推荐在生产环境使用。


内容的提问来源于stack exchange,提问作者HiroIshida

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 17:36:27