ベストアンサー1
Python >= 3.6
Python 3.6以降では、dict読み込み中特別な辞書型がない限り、順序はデフォルトで保持されます。デフォルトのダンパー一方、 は辞書をキーでソートします。 から始めてpyyaml 5.1
、 を渡すことでこれをオフにすることができますsort_keys=False
:
a = dict(zip("unsorted", "unsorted"))
s = yaml.safe_dump(a, sort_keys=False)
b = yaml.safe_load(s)
assert list(a.keys()) == list(b.keys()) # True
これは、新しい辞書の実装これは、pypyで長い間使用されてきたものです。CPython 3.6ではまだ実装の詳細と考えられていましたが、3.7以降では「辞書の挿入順序保存の性質はPython言語仕様の公式な一部として宣言されました」。Python 3.7 の新機能。
これは PyYAML 側ではまだ文書化されていないため、安全性が重要なアプリケーションではこれに依存すべきではないことに注意してください。
元の回答(すべての既知のバージョンと互換性あり)
私は@Jamesが好きです解決シンプルさのためです。ただし、デフォルトのグローバルyaml.Loader
クラスが変更されるため、厄介な副作用が発生する可能性があります。特に、ライブラリ コードを書く場合、これは良い考えではありません。また、 では直接動作しませんyaml.safe_load()
。
幸いなことに、この解決策はそれほど労力をかけずに改善できます。
import yaml
from collections import OrderedDict
def ordered_load(stream, Loader=yaml.SafeLoader, object_pairs_hook=OrderedDict):
class OrderedLoader(Loader):
pass
def construct_mapping(loader, node):
loader.flatten_mapping(node)
return object_pairs_hook(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping)
return yaml.load(stream, OrderedLoader)
# usage example:
ordered_load(stream, yaml.SafeLoader)
シリアル化には、次の関数を使用できます。
def ordered_dump(data, stream=None, Dumper=yaml.SafeDumper, **kwds):
class OrderedDumper(Dumper):
pass
def _dict_representer(dumper, data):
return dumper.represent_mapping(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
data.items())
OrderedDumper.add_representer(OrderedDict, _dict_representer)
return yaml.dump(data, stream, OrderedDumper, **kwds)
# usage:
ordered_dump(data, Dumper=yaml.SafeDumper)
いずれの場合も、カスタム サブクラスをグローバルにして、呼び出しごとに再作成する必要がないようにすることもできます。