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

如何在Pydantic中使用抽象基类子类实现多态列表?

解决Pydantic继承场景下子类字段被忽略的问题

这个问题是Pydantic处理多态类型时的常见情况——默认情况下,当你声明父类类型的列表时,Pydantic只会解析父类定义的字段,子类的额外字段会被直接丢弃。要让events正确成为Base子类的实例列表,有两种实用的解决方法:

方法1:使用鉴别器(Discriminator,推荐Pydantic v2+)

这是Pydantic官方推荐的多态处理方案,通过添加一个鉴别字段让Pydantic自动识别不同子类。步骤如下:

  1. 在父类Base中定义一个鉴别字段(比如type),用来区分不同子类;
  2. 每个子类固定这个字段的取值,标识自身类型;
  3. 用Annotated+Union结合Discriminator定义子类的联合类型;
  4. 在Response中使用这个联合类型的列表。

完整代码示例:

from abc import ABC
from typing import List, Annotated, Union
from pydantic import BaseModel, Discriminator

class Base(BaseModel, ABC):
    common: int
    type: str  # 鉴别字段,用于区分子类

class Child1(Base):
    child1: int
    type: str = "child1"  # 固定子类标识

class Child2(Base):
    child2: int
    type: str = "child2"

# 定义带鉴别器的联合类型,指定用`type`字段判断子类
Event = Annotated[Union[Child1, Child2], Discriminator("type")]

class Response(BaseModel):
    events: List[Event]

# 注意传入的字典要包含`type`字段
events = [
    {'common':1, 'type': 'child1', 'child1': 10},
    {'common': 2, 'type': 'child2', 'child2': 20}
]
resp = Response(events=events)
print(resp.events)
# 输出:[Child1(common=1, type='child1', child1=10), Child2(common=2, type='child2', child2=20)]

这样Pydantic就能根据type字段的值自动匹配对应的子类,完整保留所有字段。

方法2:手动解析子类实例(无需修改模型结构)

如果不想在模型中添加额外的鉴别字段,可以手动判断每个字典的字段,将其解析为对应的子类实例,再传入Response:

from abc import ABC
from typing import List
from pydantic import BaseModel, parse_obj_as

class Base(BaseModel, ABC):
    common: int

class Child1(Base):
    child1: int

class Child2(Base):
    child2: int

class Response(BaseModel):
    events: List[Base]

events = [{'common':1, 'child1': 10}, {'common': 2, 'child2': 20}]

# 手动解析每个事件到对应子类
parsed_events = []
for event in events:
    if 'child1' in event:
        parsed_events.append(Child1(**event))
    elif 'child2' in event:
        parsed_events.append(Child2(**event))

resp = Response(events=parsed_events)
print(resp.events)
# 输出:[Child1(common=1, child1=10), Child2(common=2, child2=20)]

这种方式的缺点是需要自己维护字段和子类的映射关系,当子类较多时会比较繁琐,但胜在不需要修改原有模型结构。

补充:如果使用Pydantic v1,鉴别器的语法略有不同,需要在Union类型中通过Field(discriminator="type")配置,或者在模型的Config类中设置discriminator字段,核心逻辑是一致的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:14:21