为啥在子类化 Pydantic BaseModel 时会出现“AttributeError:__fields_set__”?

Posted

技术标签:

【中文标题】为啥在子类化 Pydantic BaseModel 时会出现“AttributeError:__fields_set__”?【英文标题】:Why do I get "AttributeError: __fields_set__" when subclassing a Pydantic BaseModel?为什么在子类化 Pydantic BaseModel 时会出现“AttributeError:__fields_set__”? 【发布时间】:2020-05-26 05:47:09 【问题描述】:

我有这个项目,我的基类和子类实现了pydantic.BaseModel

from pydantic import BaseModel
from typing import List
from dataclasses import dataclass

@dataclass
class User(BaseModel):
    id: int 

@dataclass
class FavoriteCar(User):
    car_names: List[str] 

car = FavoriteCar(id=1, car_names=["Acura"])
print(f"car.id car.car_names[0]")

但是出现了这个错误:

    self.__fields_set__.add(name)
E   AttributeError: __fields_set__

有人介意解释发生了什么吗?我之所以要使用 pydantic,是因为我需要一种方法来快速将 Python 对象转换为dict(或 JSON)并返回。

【问题讨论】:

我用一个更好的例子更新了帖子。这类似于我的 src 中的代码。 看起来你可以在没有子类 FavoriteCardataclassBaseModel 冲突的情况下重现这个。 我之前没有提供完整的示例。感谢大家的帮助,我解决了这个问题。您不能将@dataclass 装饰器与 pydantic 一起使用,我不能 100% 确定为什么,但这可能是因为 pydantic 对后台带注释的数据做了一些特殊的事情。 好像我跳过了一些非常重要的事情:pydantic-docs.helpmanual.io/usage/dataclasses 【参考方案1】:

您需要决定是继承自pydantic.BaseModel,还是使用@dataclass 装饰器(from dataclassesfrom pydantic.dataclasses)。

两者都可以,但不能同时使用,根据documentation(我添加的粗体):

如果您不想使用 pydantic 的 BaseModel,您可以改为在标准数据类上获得相同的数据验证

【讨论】:

谢谢!我已经从数据类转换为 BaseModel 并忘记了装饰器。【参考方案2】:
E   AttributeError: __fields_set__

Peter T 已经回答了您问题的第一部分,Document 说 - “请记住,pydantic.dataclasses.dataclass 是 dataclasses.dataclass 的直接替代品”

第二部分是您想将它们转换为 dict。

我之所以要使用 pydantic,是因为我需要一种方法来快速将 Python 对象转换为 dict(或 JSON)并返回

要回答您问题的这一部分,您可以使用数据类本身的asdict source

from dataclasses import dataclass, asdict
from typing import List


@dataclass
class Point:
     x: int
     y: int

@dataclass
class C:
     l: List[Point]

p = Point(10, 20)
assert asdict(p) == 'x': 10, 'y': 20

c = C([Point(0, 0), Point(10, 4)])
assert asdict(c) == 'l': ['x': 0, 'y': 0, 'x': 10, 'y': 4]

关于这些模块级辅助函数(.asdict.astuple)的讨论表明它们不符合 PEP8(应该是 as_dict()as_tuple())但最终他们决定与 namedtuple._asdict() 保持一致和 attr.asdict()。 source

【讨论】:

以上是关于为啥在子类化 Pydantic BaseModel 时会出现“AttributeError:__fields_set__”?的主要内容,如果未能解决你的问题,请参考以下文章

pydantic学习与使用-2.基本模型(BaseModel)使用

使用外部类或字典创建 pydantic.BaseModel 定义

pydantic学习与使用-14.exclude_unset去掉未传值的字段

pydantic学习与使用-14.exclude_unset去掉未传值的字段

pydantic学习与使用-11.pycharm插件pydantic 语法提示功能

如何使用 Pydantic 解析模型列表