gpt4 book ai didi

python - 区分相同字段的 Pydantic 模型

转载 作者:行者123 更新时间:2023-12-04 11:25:26 27 4
gpt4 key购买 nike

我正在使用 Pydantic 来定义分层数据,其中有具有相同属性的模型。
但是,当我保存和加载这些模型时,Pydantic 无法再区分使用了哪个模型,而是选择了字段类型注释中的第一个。
我知道这是基于 documentation 的预期行为.
但是,类类型信息对我的应用程序很重要。
在 Pydantic 中区分不同类的推荐方法是什么?一个技巧是简单地向其中一个模型添加一个无关字段,但我想找到一个更优雅的解决方案。
请参阅下面的简化示例:container用类型 DataB 的数据初始化,但是导出加载后,新的container具有 DataA 类型的数据因为它是 container.data 类型声明中的第一个元素.
谢谢你的帮助!

from abc import ABC
from pydantic import BaseModel #pydantic 1.8.2
from typing import Union

class Data(BaseModel, ABC):
""" base class for a Member """
number: float

class DataA(Data):
""" A type of Data"""
pass

class DataB(Data):
""" Another type of Data """
pass

class Container(BaseModel):
""" container holds a subclass of Data """
data: Union[DataA, DataB]

# initialize container with DataB
data = DataB(number=1.0)
container = Container(data=data)

# export container to string and load new container from string
string = container.json()
new_container = Container.parse_raw(string)

# look at type of container.data
print(type(new_container.data).__name__)
# >>> DataA

最佳答案

正如评论中正确指出的那样,在解析时无法区分没有存储附加信息的模型。
截至今天(pydantic v1.8.2),在 Union 中解析时区分模型的最规范方法(在歧义的情况下)是显式添加类型说明符 Literal .它看起来像这样:

from abc import ABC
from pydantic import BaseModel
from typing import Union, Literal

class Data(BaseModel, ABC):
""" base class for a Member """
number: float


class DataA(Data):
""" A type of Data"""
tag: Literal['A'] = 'A'


class DataB(Data):
""" Another type of Data """
tag: Literal['B'] = 'B'


class Container(BaseModel):
""" container holds a subclass of Data """
data: Union[DataA, DataB]


# initialize container with DataB
data = DataB(number=1.0)
container = Container(data=data)

# export container to string and load new container from string
string = container.json()
new_container = Container.parse_raw(string)


# look at type of container.data
print(type(new_container.data).__name__)
# >>> DataB
此方法可以自动化,但您可以自行负责使用它,因为它破坏了静态类型并使用在 future 版本中可能会更改的对象:
from pydantic.fields import ModelField

class Data(BaseModel, ABC):
""" base class for a Member """
number: float

def __init_subclass__(cls, **kwargs):
name = 'tag'
value = cls.__name__
annotation = Literal[value]

tag_field = ModelField.infer(name=name, value=value, annotation=annotation, class_validators=None, config=cls.__config__)
cls.__fields__[name] = tag_field
cls.__annotations__[name] = annotation


class DataA(Data):
""" A type of Data"""
pass


class DataB(Data):
""" Another type of Data """
pass

关于python - 区分相同字段的 Pydantic 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69322097/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com