Это поведение работает как задумано. Вы сбрасываете существующий объект, поэтому при загрузке pyyaml намеренно избегает инициализации объекта снова. Прямые атрибуты выгруженного объекта будут сохранены, даже если они созданы в __post_init__
, потому что эта функция выполняется до сброса. Если вы хотите получить побочные эффекты __post_init__
, такие как оператор печати в вашем примере, вам нужно убедиться, что инициализация происходит.
Есть несколько способов сделать это sh. Вы можете использовать метакласс или добавить подходы конструктора / представления, описанные в документации pyyaml . Вы также можете вручную изменить выведенную строку в вашем примере так, чтобы она была '' !! python / object / new: 'вместо' '!! python / object:'. Если вашей конечной целью является создание файла yaml другим способом, то это может быть решением.
См. Ниже обновление вашего кода, который использует подход метакласса и вызывает __post_init__
при загрузке из сброшенный объект класса. Вызов cls(**fields)
в from_yaml
гарантирует, что объект инициализирован. yaml.load
использует cls.__new__
для создания объектов, помеченных '' !! 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_))