1. ホーム
  2. python

PyYAML はアルファベット順でない dict アイテムをダンプできますか?

2023-08-03 22:32:53

質問

私は yaml.dump を使ってディクショナリーを出力しています。 キーに基づきアルファベット順に各項目を出力しています。

>>> d = {"z":0,"y":0,"x":0}
>>> yaml.dump( d, default_flow_style=False )
'x: 0\ny: 0\nz: 0\n'

キーと値のペアの順序を制御する方法はありますか?

私の特定のユースケースでは、逆方向の印刷は(偶然にも)十分によいでしょう。 しかし、完全を期すために、私は、より正確に順序を制御する方法を示す答えを探しています。

私は collections.OrderedDict を使うことを検討しましたが、PyYAMLはそれをサポートしていない(ように見える)。 また、サブクラスとして yaml.Dumper のサブクラス化も検討しましたが、項目の順序を変更する機能があるかどうかはわかりませんでした。

どのように解決するのですか?

もっと良い回避策があると思うのですが、ドキュメントやソースには何も書かれていませんでした。


Python 2 (コメントを見る)

私はサブクラス化した OrderedDict をサブクラス化し、ソート不能な項目のリストを返すようにしました。

from collections import OrderedDict

class UnsortableList(list):
    def sort(self, *args, **kwargs):
        pass

class UnsortableOrderedDict(OrderedDict):
    def items(self, *args, **kwargs):
        return UnsortableList(OrderedDict.items(self, *args, **kwargs))

yaml.add_representer(UnsortableOrderedDict, yaml.representer.SafeRepresenter.represent_dict)

で、うまくいくようです。

>>> d = UnsortableOrderedDict([
...     ('z', 0),
...     ('y', 0),
...     ('x', 0)
... ])
>>> yaml.dump(d, default_flow_style=False)
'z: 0\ny: 0\nx: 0\n'


Python 3 または 2 (コメントを見る)

カスタムプレゼンターを書くこともできますが、そこからスタイルチェックのコードを取り除いたので、後で問題が発生するかどうかわかりません。

import yaml

from collections import OrderedDict

def represent_ordereddict(dumper, data):
    value = []

    for item_key, item_value in data.items():
        node_key = dumper.represent_data(item_key)
        node_value = dumper.represent_data(item_value)

        value.append((node_key, node_value))

    return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', value)

yaml.add_representer(OrderedDict, represent_ordereddict)

しかし、これでは、ネイティブの OrderedDict クラスを使用することができます。