如何在Pydantic中为包含多态成员的模型指定实际类以完成序列化与反序列化
如何在Pydantic中为包含多态成员的模型指定实际类以完成序列化与反序列化
你遇到的问题本质是Pydantic在反序列化时,不知道要把JSON里的widget数据转换成哪个具体的子类——因为你声明的字段类型是抽象基类I_Widget,它自然无法直接实例化抽象类。你看到的报错:
TypeError: Can't instantiate abstract class I_Widget without an implementation for abstract method 'do_stuff'就是这个原因导致的。
解决这个问题的核心是给Pydantic一个“线索”,让它能区分不同的子类并正确实例化,Pydantic官方推荐的方式是使用**鉴别器(discriminator)**机制,下面是具体的修改方案:
步骤说明
- 第一步:在抽象基类
I_Widget中添加一个用于区分子类的字段(比如widget_type),并在模型配置中指定这个字段为鉴别器。 - 第二步:让每个子类都设置这个字段的固定值,这样Pydantic就能通过这个值识别对应的子类。
修改后的完整代码
from abc import ABC, abstractmethod from pydantic import BaseModel, TypeAdapter, Field from typing import Literal class I_Widget(ABC, BaseModel): # 添加鉴别器字段,用Literal限定可能的子类标识值 widget_type: Literal["actual_widget"] = Field(..., discriminator="widget_type") @abstractmethod def do_stuff(self): ... # 配置模型,指定鉴别器字段 model_config = {"discriminator": "widget_type"} class WidgetHolder(BaseModel): widget: I_Widget class ActualWidget(I_Widget): # 固定当前子类的鉴别器字段值 widget_type: Literal["actual_widget"] = "actual_widget" value: int def do_stuff(self): print('Doing stuff') if __name__ == '__main__': w = ActualWidget(value=42) wh = WidgetHolder(widget=w) # 序列化:JSON中会包含widget_type字段 json = wh.json() print("序列化后的JSON:", json) # 反序列化:Pydantic会根据widget_type自动匹配ActualWidget wh2 = TypeAdapter(WidgetHolder).validate_json(json) print("反序列化后的widget类型:", type(wh2.widget)) # 输出 <class '__main__.ActualWidget'> wh2.widget.do_stuff() # 正常执行,打印 "Doing stuff"
扩展说明
如果后续需要添加更多子类(比如AnotherWidget),只需要重复以下步骤:
- 在基类
I_Widget的Literal中添加新的标识值,比如"another_widget" - 创建新子类并固定
widget_type的取值,示例如下:
class AnotherWidget(I_Widget): widget_type: Literal["another_widget"] = "another_widget" name: str def do_stuff(self): print(f'Doing stuff with {self.name}')
这样Pydantic就能自动处理新子类的序列化与反序列化,无需修改其他逻辑。
备注:内容来源于stack exchange,提问作者Adam Ryczkowski
相关产品推荐
相关产品推荐

