🐍
python + yaml 辞書順序問題
python + yaml で辞書(Dict)の順序を維持するということで、改めて調べてみた。
pythonのDictは順序を維持する 3.7以降
pythonのDictは挿入順を維持しないことが有名だったと思うが、もう古いらしい。3.7以降は維持する。
じゃあOrderdDictは不要かというと、そんなこともないらしい。公式にもあるが、
- Dictどうしで比較する
- 順序もちゃんと見る必要がある
は以前Orderdが必要のようだ。まあ、めったにないと思うけど
3.7以降でも PyYAMLだと順序狂うぞ?
import yaml as c_yaml
d = {"hoge": "fuga", "a": 10, "c": 120, "b": 0 }
c_yaml.safe_(d)
print(c_yaml.safe_dump(d))
a: 10
b: 0
c: 120
hoge: fuga
並び替えしてるぞ。ちょっと調べたら、sale_dumpに引数送ればいいらしい
print(c_yaml.safe_dump(d, sort_keys=False))
hoge: fuga
a: 10
c: 120
b: 0
ほんまや
他のライブラリruamel.yaml はどうや?
ruamel.yamlを試してみた。Loadから
from ruamel.yaml import YAML
inp = """\
# example
name:
# details
family: Smith # very common
given: Alice # one of the siblings
"""
yaml = YAML()
yaml.load(inp)
Out[X]: ordereddict([('name', ordereddict([('family', 'Smith'), ('given', 'Alice')]))])
いきなりOrderdDictでくるのか。OrderdのDumpは想像どおり、順序維持したので、敢えてDictをDumpしてみる
d = {"hoge": "fuga", "a": 10, "c": 120, "b": 0 }
import sys
yaml.dump(d, sys.stdout)
hoge: fuga
a: 10
c: 120
b: 0
Dictでもとくに何もせずとも維持された。
jsonはどうや?
d = {"hoge": "fuga", "a": 10, "c": 120, "b": 0 }
import json
json.dumps(d)
# Out[x]: '{"hoge": "fuga", "a": 10, "c": 120, "b": 0}'
json.dumps(d, sort_keys=True)
# Out[x]: '{"a": 10, "b": 0, "c": 120, "hoge": "fuga"}'
デフォルトで sort_keys=False のようです。 yamlと仕様が逆。
学び
- 辞書の順序が狂うのはPythonの昔からの仕様ではなくて、Python単体だと辞書順序は維持される、3.7からは
- 辞書の順序が狂うではなく、PyYamlにアルファベット順に並べ替えられていた
- そもそもPython単体で辞書の順番変わるのはアルファベット順ではなく、ランダム
- jsonはデフォルトでアルファベットで並び替えをしない、PyYAMLと逆になっていたのが不幸
Discussion