2

私はファイルPyYamlを出力するために使用しYAMLます。しかし、それは私のアイテムを並べ替えます。次のように

>>> yaml.dump({'3':5, '1':3})
"{'1': 3, '3': 5}\n"

私は取得したい"{'3': 5, '1': 3}\n"。私はそのことをすることができます

PS。を試してみましたcollections.OrderedDict。その出力は良くありません。フォロー中のように

>>> a= collections.OrderedDict()
>>> a['3']=1
>>> a['1']=2
>>> a['5']=2
>>> yaml.dump(a)
"!!python/object/apply:collections.OrderedDict\n- - ['3', 1]\n  - ['1', 2]\n  - ['5', 2]\n"
4

2 に答える 2

4

TL;DR: 解決策は、「LOOK HERE!」とコメントされた 2 行にあります。出力がリストのリストになることを受け入れれば、YAML をプログラム内の辞書として扱い、保存されたファイル/テキストの順序で扱うことができます。

!!python/ordered_dict や !!omap のような恐ろしく醜い明示的な型を気にしない場合は、ファイルをポイ捨てすることもできます。私の投票は!!omapに行きますが、それをサポートするツール/ライブラリの数はわかりません(!!python/ordered_dictをサポートするツールは少ないと確信しています)。最終的に、dict 自体と、キーの順序を定義するメタデータの 2 つの独立したデータ セットを処理します。

(どこでも !!python/ordered_dict または !!omap 混乱なしで YAML で順序付けられた辞書を強制する半魔法の方法がありますが、それらは壊れやすく、辞書の定義そのものと矛盾し、基礎となる YAML ライブラリが進化するにつれて壊れる可能性がありますちなみに、この状況は JSON の場合と同じです。YAML は JSON のスーパーセットであり、キーの順序を保証しないためです。つまり、標準準拠のツール/ユーザーが初めてファイルをいじると、回避策が機能しなくなります。)

この投稿の残りの部分は、例/検証コードと、なぜこのようになっているのかの説明です。

from __future__ import print_function
import yaml

# Setting up some example data
d = {'name': 'A Project',
     'version': {'major': 1, 'minor': 4, 'patch': 2},
     'add-ons': ['foo', 'bar', 'baz']}

# LOOK HERE!
ordering = ['name', 'version', 'add-ons', 'papayas']
ordered_set = [[x, d[x]] for x in ordering if x in d.keys()]
# In the event you only care about a few keys,
# you can tack the unspecified ones onto the end
# Note that 'papayas' isn't a key. You can establish an ordering that
# includes optional keys by using 'if' as a guard in the list comprehension.

# Demonstration
things = {'unordered.yaml': d, 'ordered.yaml': ordered_set}
for k in things:
    f = open(k, 'w')
    f.write(yaml.dump(things[k], default_flow_style=False, allow_unicode=True))
    f.close()

# Let's check the result
output = []
for k in things:
    f = open(k, 'r')
    output.append(dict(yaml.load(f.read())))
    f.close()

# Should print 'OK'
if output[0] == output[1]:
    print('OK')
else:
    print('Something is wrong')

作成されたファイルは次のようになります。

注文した.yaml:

- - name
  - A Project
- - version
  - major: 1
    minor: 4
    patch: 2
- - add-ons
  - - foo
    - bar
    - baz

unordered.yaml:

add-ons:
- foo
- bar
- baz
name: A Project
version:
  major: 1
  minor: 4
  patch: 2

これは、期待するほどきれいな YAML ドキュメントを生成しません。そうは言っても、最初の入力としてかなりの YAML を使用できます (やった!)。きれいではない順序付けられた YAML から、きれいで順序付けられたままの dict スタイルの YAML への変換のスクリプトを作成するのは簡単です (これは演習として残しておきます)。 .

保持したいキーの順序がある場合は、それを順序付きリスト/タプルに書き込みます。そのリストを使用して、リストの順序付きリストを生成します (ただし、YAML で !!python/tuple タイプを取得するため、タプルのリストではありません)。それを YAML にダンプします。それを通常どおりに読み戻すには、その構造体を dict() に渡すと、最初に使用した元の辞書に戻ります。順序を保持する必要があるネストされた構造がある場合は、構造を再帰的に下降する必要がある場合があります (これは、散文で説明するよりもコードで行う方が簡単です。これはおそらく既に知っていることです)。

この例では、プロジェクトの「名前」をファイルの最初に配置し、次に「バージョン」番号の要素、次に「アドオン」を配置します。通常、PyYAML は dump() を呼び出すときに辞書キーを英数字順に並べますが、これは将来変更される可能性があり、YAML 標準にはこれを必要とするものがないため、これは信頼できません。このように物事を行います。「アドオン」が「名前」の前に来るので、順序付けに問題があります。だから私は自分の順序を定義し、リストの順序付きリストをパックし、それをダンプします。

本質的に順序付けられていないものから順序付けを求めています。ディクショナリは、検索速度のために内部的に順序付けられたハッシュ テーブルです。明日、辞書を実装するより高速な方法が発見された場合、ランタイムは、辞書がハッシュテーブルの有用な抽象化であることに依存するすべてのコードを壊すことなく、それを実装する必要があるため、その順序を台無しにすることはできません。

同様に、YAML はマークアップ言語ではなく (元は「Yaml Ain't a Markup Language」の略でした)、データ形式です。違いは重要です。タプルやリストなど、一部のデータは順序付けされています。キーと値のペアのバッグのように、そうでないものもあります (ハッシュ テーブルとは少し異なりますが、概念的には似ています)。

この種のソリューションの再帰バージョンを使用して、人間が読みやすくするためではなく、さまざまな YAML 実装で YAML 出力を保証しますが、YAML で多くのデータを渡す必要があり、各レコードはキーで署名する必要があり、無期限の順序で防ぐことができます。辞書/ハッシュが使用されているときはいつでも統一された署名。

于 2014-03-12T14:08:32.073 に答える