2012-03-31 4 views
1

だから私はたくさんのトリビアの質問と答えのリストを持つyamlファイルを持っています。しかし、私はこのファイルを読み込み、pyyamlでpythonで内容をダンプしようとすると、それらを逆方向にダンプします。私はそれが私のyamlファイルかどうか、私はライブラリに何か間違っているかどうかはわかりません。PyYamlのものを後ろにダンプする

のは私の質問/回答のペアの一つが、YAMLファイルに次のようになりますことを言ってみましょう -

{"question": "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...", 
"answer": ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"]} 

私はPythonの辞書にyaml.dump()を使用すると、それはこのダンプ -

answer: [fibonacci, padovan, morris]\nquestion: 'what sequence is this: 1, 1, 2, 3, 5, 8, 13, ...'\n" 

私はこれを期待していた -

- question: "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ..." 
    answer: ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"] 

私はここで何か間違ったことをやっていますか?

答えて

2

YAML連想配列(およびPythonディクショナリ)は、要素の順序を保持しません。

>>> yaml.load('''!!omap 
... - a: foo 
... - b: bar''') 
[('a','foo'),('b','bar')] 

This answerPython OrderedDictにそれらに!!omapをロードする方法についていくつかの詳細を与える:注文がインポートされた場合

しかし、その後、YAMLはタプルのリストに解析し、デフォルトによってPyYAMLとordered map !!omapは、例えば定義します。

+0

ありがとう、私は何か間違っていると私はちょうどそれが何だったのか分からなかった。 –

1

辞書として読み込んでいる場合、その順序は任意です。辞書は順序付きのコンテナではありません。

+0

私が何を重要なの私はそれらをダンプする方法である、ということを知っています。私が示したダンプされた文字列は、文字列として表現された、あるいは正しくフォーマットされた答えを持っていません(最初のものの - infrontで)。 –

+0

@Matt、PyYAMLは基本的にYAMLローダー/ダンパーのリファレンス実装です。そのような共通の操作です)、その出力は標準に従います。 – huon

6

ここでは多少異なる答えがあります。可読性以外の理由で要素の順序が重要である場合、dbauppの答え​​は正しいです。答えが出る前に質問を表示させたいだけの理由があれば、ファイルを人間が読めるようにする必要がある場合は、!! omapを使う必要はなく、代わりにカスタム表現を使って望みの注文を得ることができます。

まず、ダンピングダンピングの問題は、リストの代わりに1つのマッピングだけをダンプしているためです。あなたの辞書をリストの中に入れてください。これは修正されます。だから我々はで始まる:

d = [{"question": "What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...", 
"answer": ["The Fibonacci Sequence", "The Padovan Sequence", "The Morris Sequence"]}] 

今、私たちは出力になりたいので、私たちがいることを指定し、その順序でOrderedDictに変換します特定の順序があります。

from collections import OrderedDict 
order = ['question', 'answer'] 
do = [ OrderedDict(sorted(z.items(), key=lambda x: order.index(x[0]))) for z in d ] 

次に、我々 PyYAMLがOrderedDictと何をするべきかを知るようにする必要があります。この場合、私たちはそれが!! omapであることを望んでいません。特定の順序でマッピングするだけです。 dumper.represent_mappingにitems属性を持つdumper.represent_mappingを指定すると、ダンプする前にアイテムをソートしますが、item()の出力を与えると(例えば、(key 、値)タプル)、それはしません。したがって、私たちは

def order_rep(dumper, data): 
    return dumper.represent_mapping(u'tag:yaml.org,2002:map', data.items(), flow_style=False) 
yaml.add_representer(OrderedDict, order_rep) 

を使用することができます。そして、print yaml.dump(do)から私たちの出力のように終わる:

- question: 'What is the name of this sequence of numbers: 1, 1, 2, 3, 5, 8, 13, ...' 
    answer: [The Fibonacci Sequence, The Padovan Sequence, The Morris Sequence] 

これを行うことができ、多数の異なる方法があります。 OrderedDictを使用することは、実際には必要ではありませんが、あなたは代理人を書くことができるいくつかのクラスの質問/回答のペアが必要です。

また、これは人間の読みやすさと美的目的のためだけであることを理解してください。 !! omapを使用していた場合のように、ここでの順序はYAMLの重要な意味を持ちません。読みやすさのためにこれが第一に重要だったようです。

4

ダンプに好適な場合順序は、コードの下に

import yaml 

class MyDict(dict): 
    def to_omap(self): 
     return [('question', self['question']), ('answer', self['answer'])] 

def represent_omap(dumper, data): 
    return dumper.represent_mapping(u'tag:yaml.org,2002:map', data.to_omap()) 

yaml.add_representer(MyDict, represent_omap) 

questions = [ 
    MyDict({'answer': 'My name is Bob.', 'question': 'What is your name?'}), 
    MyDict({'question': 'How are you?', 'answer': 'I am fine.'}), 
] 
print yaml.dump(questions, default_flow_style=False) 

を使用することができた場合、出力は次のようになります。

- question: What is your name? 
    answer: My name is Bob. 
- question: How are you? 
    answer: I am fine. 
+0

+1これはきちんとしていて、うまくいきます。私は 'Representative'を' MyDict'に '@ staticmethod'として持っていて、物事をまとめるのが好きです。したがって、代わりに 'yaml.add_representer(MyDict、MyDict.representer)'を実行します。 – Day

+0

しかし、これは 'yaml.safe_dump'でダンプするときには機能しません。上記のように 'safe_dump' **と**カスタム表現をどのように使うことができますか?私は例外があります: 'yaml.representer.RepresenterError:オブジェクトを表すことはできません:{'答え': '私の名前はボブです'、 '質問':あなたの名前は何ですか? '}' – Day

+0

: 'yaml.add_representer(...) 'の代わりに' yaml.SafeDumper.add_representer(...) 'を使用してください – Day

関連する問題