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。