Python では、YAML マッピングを OrderedDicts としてロードするにはどうすればよいでしょうか? 質問する

Python では、YAML マッピングを OrderedDicts としてロードするにはどうすればよいでしょうか? 質問する

私は取得したいpyYAML とはのローダーは、マッピング(および順序付きマッピング)をPython 2.7以降にロードします。順序付き辞書バニラdictと現在使用しているペアのリストの代わりに、タイプを使用します。

それを実行する最善の方法は何ですか?

ベストアンサー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)

いずれの場合も、カスタム サブクラスをグローバルにして、呼び出しごとに再作成する必要がないようにすることもできます。

おすすめ記事