我有两个数据类:Msg和Field。Msg 有一个fields类型字段list[Field]。我想在它们全部初始化后为每个字段分配一些内容,Field这或多或少是它们在列表中的相对索引fields。
Msg
Field
fields
list[Field]
但是,当我__post_init__(self)向Msg数据类添加方法时,fields列表为空,因此我无法更新索引。
__post_init__(self)
from dataclasses import dataclass from ruamel.yaml import YAML @dataclass class Msg: id: int desc: str fields: list[Field] def __post_init__(self) -> None: idx: int = 0 for field in self.fields: # why is this empty?? field.index = idx idx += field.size @dataclass class Field: id: int name: str units: str size: int index: int = -1 y = YAML() y.register_class(Msg) y.register_class(Field) msg: Msg = y.load("""\ !Msg id: 1 desc: status fields: - !Field id: 1 name: Temp units: degC size: 2 """) assert(msg.fields[0].index != -1) # fails :(
为什么是这样?Msg未初始化的情况下如何初始化fields?有什么办法可以使用班级系统来做我想做的事情吗?我在 MacOS 上使用 Python 3.11 和 ruamel.yaml 0.18.5。
默认情况下,对象序列化程序(例如 YAML)pickle不知道如何处理用户定义对象的属性映射,除了按原样将映射直接分配给对象的属性字典之外。
pickle
这就是为什么您可以__setstate__为您的类定义一个方法,以便ruamel.yaml在这种情况下,对象构造函数知道使用__init__解包为参数的映射来调用该方法,这反过来又调用__post_init__后初始化:
__setstate__
ruamel.yaml
__init__
__post_init__
@dataclass class Msg: id: int desc: str fields: list[Field] def __post_init__(self) -> None: idx: int = 0 for field in self.fields: field.index = idx idx += field.size def __setstate__(self, state): self.__init__(**state)