kazasiki's blog

プログラミングとかVRゲームとか

dataclass-wizardを使ってyamlをdataclassの値に変換する

Pythonに限らずプログラムを書いてれば固定値の集まりをJSONYAMLなどの別ファイルに分けたいことがあると思います。今回はそんな時に便利なライブラリとしてJSONYAMLをdataclassにmarshalしてくれるdataclass-wizardをご紹介します。

背景

PythonYAMLを読み込んで扱う場合、普通はPyYAMLを使いますが、例えば yaml.load の戻り値はdict型になってしまいます。そこから値を取り出す場合も、 dict["key"] などといった風にキーを指定する形になります。

これでも問題ないかも知れませんが、キーの名前に対するIDEやエディタの補完が効かなかったり、まとまった値を関数に渡す場合もdict型になってしまうので、関数の方で何のキーを指定すれば良いのか分かりづらくなる原因になります。

そこでJSONYAMLを読み込んでdataclassの値にmarshalするdataclass-wizardを使います。

github.com

大まかな機能

例えば、以下のようなpythonのコードとYAMLファイルを用意します。

from dataclasses import dataclass, field
from dataclass_wizard import YAMLWizard

@dataclass
class MyNestedClass:
    list_of_map: list[dict[int, str]] = field(default_factory=list)
    my_int: int = 14

@dataclass
class MyClass(YAMLWizard):
    str_or_num: str | int = 42
    nested: MyNestedClass | None = None

    @property
    def sum(self):
        return self.str_or_num + self.nested.my_int
str-or-num: 23
nested:
    ListOfMap:
        - 111: Hello,
          222: World!
        - 333: 'Testing'
          444: 123

以下のコードでYAMLファイル読み込んでMyClassのオブジェクトを生成できます。

obj = MyClass.from_yaml_file('my_file.yml')
ob.str_or_num # => 23
obj.nested.my_int # => 14
obj.sum # => 37

上記の例では、strとintのUnionTypeや、デフォルト値の設定なども含んでいますが、基本的にはそこまでの機能は必要にならないと思います。

MyClassはただのClassなのでsumメソッドのように好きなメソッドを追加することも出来ます。また、 from_yaml_file の戻り値はMyClassのオブジェクトなので、名前の補完も効きますし、型のチェックなども使えます。

dataclassの自動生成

とはいえ、YAMLファイルにあわせてdataclassを書くのが面倒くさいという人もいるでしょう。dataclass-wizardはそういう人のために、Dataclassの生成機能も持っています。

dataclass-wizard.readthedocs.io

このツールはJSONファイルからdataclassのPythonコードを自動生成してくれるものです。機能は一目瞭然なので公式のドキュメントを読めば普通に使えると思います。

ただ、YAMLには対応してないのでYAMLJSONの変換が必要になります。そういった場合は以下の記事を参考にyqなどを使って対応してください。こちらも特に難しいことはありません。

qiita.com

便利な機能ではあるものの、出力されるファイルにやや癖があるのと、一度dataclassのコードを作ってしまえばyamlとコードの平仄を取るのも大変ではないと思うので、このツールは使うのは 既に大きいYAMLファイルがあって、今からdataclass-wizardを使いたい というときだけにしたほうが良いでしょう。新規にYAMLファイルを作る場合や、YAMLに幾つかキーを追加する場合などは手動で対応してしまったほうが良いです。自分で書いたメソッドやコメントがある場合も困りますし。

まとめ

ということでdataclass-wizardの紹介でした。世の中にはdictやファイルをdataclassに変換する機能を持つライブラリが実はたくさんあるのですが、このライブラリはコードの生成機能があって気軽に導入できるので気に入ってます。JSONYAMLの設定ファイルを読み込むだけならそこまでの速度は必要ないですし、高度なvalidation機能なども不要でしょう。シンプルで使い勝手が良いライブラリなので、ぜひ使ってみてください。