はじめに
Python3でプログラムを作る際、YAML/JSONを読みだす処理を多く作成します。
そうすると、データが長く、そして複雑になる時があります。
ネストしてるデータを読みだすと以下のように
a["bbbb"]["cddddd"]["alist"][0]["qqqq"]["ddddd"]
のようにやたら長くなって、かつなんだかよく分からなくなります。
ネストしてないときはa["bbbb"]
の書き方がいい場合がありますが、長くなるとどうしても操作すべきデータが分からなくなってバグを生みやすくなります。
目標
以下の条件を満たす方法を探したいと考えています。
- dot記法でアクセス可能 (MUST)
- 例:
a.b.c.d
のようにアクセスできる。
- 例:
- 存在しないキーにアクセスした場合に例外ではなく
None
を返す (MUST)- 例:
a.b.c.e
と書いた場合、b
が存在しない場合でも例外ではなくNone
を返してほしい。
- 例:
- 高速であること (SHOULD)
- 辞書のキー順を保持する (SHOULD)
- 例: YAMLファイルで
{b: c: d: a:}
のようなデータがあった場合、キーのリストを取得するとb, c, d, a
の順で取得できる。
- 例: YAMLファイルで
- ソート可能であること (SHOULD)
- 複雑な条件でもソートできる。
- ソート前後で同一比較を行うと異なると判定される (SHOULD)
- 必ずしも異なる必要はないが、チェックはしてみる。
ライブラリ候補
上記条件に適合しそうなライブラリとして、以下を検討しました。
- 自作 + SimpleNamespace + YAML
- 使用ライブラリ:
pyyaml
(バージョン 6.0.2)
- 使用ライブラリ:
- python-box + YAML
- 使用ライブラリ:
python-box
(バージョン 7.2.3)
- 使用ライブラリ:
なお、omegaconf
という優れたライブラリもありますが、今回は実装がうまくいかなかったため割愛しました。
ファイル読み込みの場合、データが欠損することは少ないと考えられるため、今回は対象外としています。
環境
以下の環境で検証を行いました。
- WSL2: ubuntu 24.04
- Python3 3.12.3
ライブラリ候補の実装サンプル
サンプルコードはこちらに公開しています。
サンプルの動作内容は以下の通りです。
- 固定のYAMLファイルを使用
- 少し複雑なデータを用意。
- 100回ループして処理を実行
timeit
を使用して計測。
結果
以下の手順で準備を行います。
$ pip install -r requirement.txt
その後、以下のコマンドで実行します。
$ python3 ./time_test.py
box=42.12457203300437
simplenamespace=37.234188797010574
$ python3 ./time_test.py
box=42.320139449002454
simplenamespace=37.707468187989434
$ python3 ./time_test.py
box=42.18613590998575
simplenamespace=37.37725285399938
結論
- (1) SimpleNamespace + YAMLの方が早い
- (2) Boxはお手軽だけどあまり融通は利かない
最後に
自作部分のコードがやたらと長くなってしまいましたが、条件を満たす方法を見つけることができました。