🦾

YAMLWizard で順序を保ってシリアライズする

2022/10/31に公開

結論

encorder として PyYAML の safe_dump(sort_keys=False) を渡す。

import yaml as pyyaml

def encorder(data, **kw):
    return pyyaml.safe_dump(data, sort_keys=False, **kw)

obj.to_yaml_file("obj.yml", encoder=encorder)

背景

Python で dataclass を yaml で serialize/deserialize したいなと思っていたら dataclass-wizard なるライブラリを見つけました。

https://github.com/rnag/dataclass-wizard

from dataclasses import dataclass
from dataclass_wizard import YAMLWizard

@dataclass
class Kasega0(YAMLWizard):
    name: str = "kasegao"
    age: int = 23

k = Kasega0()
k.to_yaml_file("kasegao.yml")

こんな感じで手軽に yaml に dump できるのはありがたいのですが、このままだと次のように順序が保されずに出力されてしまいます。

age: 23
name: kasegao

これを元の定義順に保存してほしいなと思ったので方法を調べました。

方法

内部実装を読んでみるとデフォルトでは中で encoder として PyYAML の dump() を呼んでいるようでした。

YAMLWizard の内部実装

def to_yaml(self: T, *,
            encoder: Optional[Encoder] = None,
            **encoder_kwargs) -> AnyStr:
    """
    Converts the dataclass instance to a YAML `string` representation.
    """
    if encoder is None:
        encoder = yaml.dump

    return encoder(asdict(self), **encoder_kwargs)

よって encorder として順序を保てる safe_dump(sort_keys=False) を渡すことにしました。

import yaml as pyyaml

def encorder(data, **kw):
    return pyyaml.safe_dump(data, sort_keys=False, **kw)

k.to_yaml_file("kasegao.yml", encoder=encorder)

これで無事順序を保って serialize できるようになりました。

name: kasegao
age: 23

Discussion