Pythonに限らずプログラムを書いてれば固定値の集まりをJSONやYAMLなどの別ファイルに分けたいことがあると思います。今回はそんな時に便利なライブラリとしてJSONやYAMLをdataclassにmarshalしてくれるdataclass-wizardをご紹介します。
背景
PythonでYAMLを読み込んで扱う場合、普通はPyYAMLを使いますが、例えば yaml.load
の戻り値はdict型になってしまいます。そこから値を取り出す場合も、 dict["key"]
などといった風にキーを指定する形になります。
これでも問題ないかも知れませんが、キーの名前に対するIDEやエディタの補完が効かなかったり、まとまった値を関数に渡す場合もdict型になってしまうので、関数の方で何のキーを指定すれば良いのか分かりづらくなる原因になります。
そこでJSONやYAMLを読み込んでdataclassの値にmarshalするdataclass-wizardを使います。
大まかな機能
例えば、以下のような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には対応してないのでYAML→JSONの変換が必要になります。そういった場合は以下の記事を参考にyqなどを使って対応してください。こちらも特に難しいことはありません。
便利な機能ではあるものの、出力されるファイルにやや癖があるのと、一度dataclassのコードを作ってしまえばyamlとコードの平仄を取るのも大変ではないと思うので、このツールは使うのは 既に大きいYAMLファイルがあって、今からdataclass-wizardを使いたい
というときだけにしたほうが良いでしょう。新規にYAMLファイルを作る場合や、YAMLに幾つかキーを追加する場合などは手動で対応してしまったほうが良いです。自分で書いたメソッドやコメントがある場合も困りますし。
まとめ
ということでdataclass-wizardの紹介でした。世の中にはdictやファイルをdataclassに変換する機能を持つライブラリが実はたくさんあるのですが、このライブラリはコードの生成機能があって気軽に導入できるので気に入ってます。JSONやYAMLの設定ファイルを読み込むだけならそこまでの速度は必要ないですし、高度なvalidation機能なども不要でしょう。シンプルで使い勝手が良いライブラリなので、ぜひ使ってみてください。