2013-05-28 14 views
18

私はyaml.dumpを使ってdictを出力しています。これは、キーに基づいてアルファベット順に各項目を印刷します。PyYAMLは辞書項目をアルファベット順でダンプできますか?

>>> 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のサブクラスを見てきましたが、アイテムの順序を変更できるかどうかはわかりませんでした。

+1

ソースを見ると強制的にdictをソートするように見えるので、 'yaml.add_representer'を呼び出すことはできません。 – Blender

答えて

32

おそらくもっと良い解決策がありますが、ドキュメントやソースで何も見つかりませんでした。


のPython 2(コメントを参照してください)

私はOrderedDictをサブクラス化し、それがunsortable項目のリストを返す作っ:

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(コメントを参照してください)

私はそれからいくつかのスタイルのチェックコードを取り除かとして、あなたはまた、カスタムrepresenterを書くことができますが、後で問題に実行されます場合、私は知りません:

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クラスを使用できます。

+0

とてもいいです、あなたのスタイルが好きです。私はそれがもう少し明確だと思うので、私は最初の解決策と一緒に行きます。私はいずれかの方法でdictを再構築する必要があります。そして、代理人の 'MappingNode'呼び出しと奇妙なunicode文字列は、それを(私にとっては)一種の不透明にします。ありがとう! – mwcz

+0

@mwcz:最初の問題の唯一の問題は 'OrderedDict'をサブクラス化することです。動作すれば動作します。 – Blender

+2

私のバージョンがPython(3.4)かどうか分かりませんが、これは動作しません。私は 'yaml/representer.py:111'のソースを見て、' mapping = sorted(mapping) 'を見ることができます。 UnsortableListの '.sort()'メソッドではなく、 'sorted'組み込み関数を使用しています。何か案は? –

2

「保存された順序でマッピングをダンプする方法」という質問に対する回答も探していました。私はpyyamlとpythonには新しいので、私は上記の解決策に従うことができませんでした。 pyyamlのドキュメントや他のフォーラムで時間を過ごした後、私はこれを見つけました。

あなたは

!! OMAPは順序を保存することによって、マッピングをダンプするためにタグを使用することができます。あなたが注文と一緒に遊びたいなら、私はあなたがキーのために行く必要があると思います:値

以下のリンクは理解を助けることができます。

https://bitbucket.org/xi/pyyaml/issue/13/loading-and-then-dumping-an-omap-is-broken

http://yaml.org/type/omap.html

+4

例として数行のコードを追加できますか?これはリンクだけの回答ではありませんが、リンクが壊れてもそれを続けることはあまりありません。サンプルコードは、私たちのためにもっと便利です。詳細については、StackOverflowスタイルに関するこの質問を参照してください:http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers(このリンクはありそうもありません腐敗へ ) –

1

あなたが望むようにこれを得るために行う必要がある2つのものがあります:それはないので

  • あなたは、dictよりも何か他のものを使用する必要がありますアイテムを注文したままにする
  • 適切な方法でその代替品をダンプする必要があります.¹

import sys 
import ruamel.yaml 
from ruamel.yaml.comments import CommentedMap 

d = CommentedMap() 
d['z'] = 0 
d['y'] = 0 
d['x'] = 0 

ruamel.yaml.round_trip_dump(d, sys.stdout) 

出力:

z: 0 
y: 0 
x: 0 

は、これは私が著者だそのruamel.yaml YAML 1.2パーサを使用して行われたを¹。

0

これは本当に@Bluenderの答えの補遺です。あなたは、単にmapping.sort()行を削除した場合、それはOrderedDict内の項目の順序を維持

def represent_mapping(self, tag, mapping, flow_style=None): 
    value = [] 
    node = MappingNode(tag, value, flow_style=flow_style) 
    if self.alias_key is not None: 
     self.represented_objects[self.alias_key] = node 
    best_style = True 
    if hasattr(mapping, 'items'): 
     mapping = mapping.items() 
     mapping.sort() 
    for item_key, item_value in mapping: 
     node_key = self.represent_data(item_key) 
     node_value = self.represent_data(item_value) 
     if not (isinstance(node_key, ScalarNode) and not node_key.style): 
      best_style = False 
     if not (isinstance(node_value, ScalarNode) and not node_value.style): 
      best_style = False 
     value.append((node_key, node_value)) 
    if flow_style is None: 
     if self.default_flow_style is not None: 
      node.flow_style = self.default_flow_style 
     else: 
      node.flow_style = best_style 
    return node 

:あなたはPyYAMLソースを見ると、representer.pyモジュールで、あなたはこの方法を見つけます。

更新:

私はFedoraプロジェクトのEPELのレポはpython2-yamlordereddictloaderというパッケージを持っていることに気づいた、と1は、同様にPythonの3のためにあります。そのパッケージの上流プロジェクトは、クロスプラットフォームの可能性が高いです。

関連する問題