Python 3.x __从yaml加载时,不会调用Python3.x数据类的post_init_uuuuu

Python 3.x __从yaml加载时,不会调用Python3.x数据类的post_init_uuuuu,python-3.x,yaml,pyyaml,python-dataclasses,Python 3.x,Yaml,Pyyaml,Python Dataclasses,请注意,我已经提到了这个问题。我发布这个问题是为了调查调用\uuuu post\u init\uuuu是否安全。请把问题核对到底 检查下面的代码。在步骤3中,我们从yaml字符串加载dataclassA。请注意,它不调用\uuu post\u init\uu方法 导入数据类 进口yaml @dataclasses.dataclass A类: a:int=55 定义后初始化(自): 打印(“\uuuuu post\uu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

请注意,我已经提到了这个问题。我发布这个问题是为了调查调用
\uuuu post\u init\uuuu
是否安全。请把问题核对到底

检查下面的代码。在步骤3中,我们从
yaml
字符串加载
dataclass
A
。请注意,它不调用
\uuu post\u init\uu
方法

导入数据类
进口yaml
@dataclasses.dataclass
A类:
a:int=55
定义后初始化(自):
打印(“\uuuuu post\uu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
打印(“\n>>>>1:创建数据类对象”)
a=a(33)
打印(a)#打印数据类
打印(数据类.字段(a))
打印(“\n>>>2:转储到yaml”)
s=yaml.dump(a)
打印#打印yaml报告
打印(“\n>>>3:从str创建类”)
a=yaml.荷载
打印(a)#打印从yaml str加载的数据类
打印(数据类.字段(a))
我现在看到的解决方案是在最后自己调用
\uuuuu-post\u init\uuuu
,如下面的代码片段所示

a_uuu.\uuuu post_uinit_uuu()

我不确定这是否是对
yaml
序列化
dataclass
的安全再现。此外,如果
数据类
字段是
数据类。InitVar
类型。

此行为按预期工作,则当
\u post\u init\u
采用kwargs时,也会产生问题。您正在转储一个现有对象,因此当您加载它时,pyyaml故意避免再次初始化该对象。转储对象的直接属性将被保存,即使它们是在
\uuuu post\u init\uuuu
中创建的,因为该函数在转储之前运行。当您想要得到来自
\uuuu post\u init\uuuu
的副作用时,如示例中的print语句,您需要确保发生初始化

实现这一点的方法很少。您可以使用元类或中描述的添加构造函数/重新输入方法。您还可以手动将示例中的转储字符串更改为“”!!python/object/new:'而不是''!!python/对象:'。如果您的最终目标是以不同的方式生成yaml文件,那么这可能是一个解决方案

有关使用元类方法并在从转储类对象加载时调用
\uuu post\u init\uuuu
的代码更新,请参见下文。从_yaml调用
中的
cls(**字段)
可确保对象已初始化
yaml.load
使用
cls.\uuuu new\uuuu
创建标记为“”的对象!!python/object:,然后手动将保存的属性加载到对象中

import dataclasses
import yaml


@dataclasses.dataclass
class A(yaml.YAMLObject):
    a: int = 55

    def __post_init__(self):
        print("__post_init__ got called", self)

    yaml_tag = '!A'
    yaml_loader = yaml.SafeLoader

    @classmethod
    def from_yaml(cls, loader, node):
        fields = loader.construct_mapping(node, deep=True)
        return cls(**fields)

print("\n>>>>>>>>>>>> 1: create dataclass object")
a = A(33)
print(a)  # print dataclass
print(dataclasses.fields(a))

print("\n>>>>>>>>>>>> 2: dump to yaml")
s = yaml.dump(a)
print(s)  # print yaml repr

print("\n>>>>>>>>>>>> 3: create class from str")
a_ = yaml.load(s, Loader=A.yaml_loader)
print(a_)  # print dataclass loaded from yaml str
print(dataclasses.fields(a_))

如果加载的东西没有实现uu post_init_uu()?我可以问一下为什么要使用YAML来保存对象而不是pickle吗?如果我不实现u_post_init__;()的话,一切都很好,但我希望在加载dataclass时这样做。我使用yaml而不是pickle,我希望在将来使用干净的yaml接口构建RESTAPI。