2012-11-08 10 views
6

yaml.loadによって呼び出される項目()の制御順序:PyYAMLと:私はデシベルでいくつかのレコードを作成し、YAML設定ファイルを持っている

setting1: 
    name: [item,item] 
    name1: text 
anothersetting2: 
    name: [item,item] 
    sub_setting: 
     name :[item,item] 

私はsetting3でこのファイルを更新し、DB内のレコードを再生成:)

import yaml 
fh = open('setting.txt', 'r') 
setting_list = yaml.load(fh) 
for i in setting_list: 
    add_to_db[i] 

それはイムはデシベルにそれらをaddigとしてそれらの順序が設定(DB内のID番号)が毎回同じとどまることが重要だ...とsetting3はちょうど(yaml.loadに付加されますそのidがすでに私のレコードを混乱させないように終わります現時点ではnはデシベル... 私は別の設定を追加し、()レコードは異なるIDになり、異なる順序でロードされますyaml.loadを呼び出すたびに。 私は abarnertヒントに続き、期待のおかげで、この主旨にhttps://gist.github.com/844388

作品を取ってきました:

EDIT);私は、任意のアイデアを歓迎します!おそらく出発点として、辞書や辞書のようなオブジェクトを受け入れるようにそれを変更するのは簡単だろうけれども

+0

まずはこの "PyYAML"、または何か他の?組み込みの 'yaml'モジュールと' yaml'モジュールを与える少なくとも2つのPyPIパッケージはありません。一般的に、サードパーティのモジュールを使用している場合は、どこから入手したかを明記する必要があります。 – abarnert

+0

あなたが使用しているモジュールが何であれ、マッピングノードをPythonに変換する方法をフックする必要があるので、 'dict'の代わりに' collection.OrderedDict'を使います。 PyYAML以外のモジュールでは、わかりません。 'PyYAML'では、これは間違いなく可能ですが、あなたが高度な便利メソッドに固執しているならば複雑です。他の誰かが、意図されたフックを使用するのではなく、それをモンキータイピングする方が簡単だと言いました。 – abarnert

+0

Imこの質問のタイトルとしてPyYAMLを使用しています... - > PyYAML:yaml.load()によって呼び出される項目の順序を制御します。アドバイスありがとうございます!! – zzart

答えて

4

YAMLの仕様は明らかにマッピング内のキーの順序をあてにすることはできません「表現の詳細」であると述べています。したがって、設定ファイルはマッピングに依存している場合は既に無効であり、可能な場合は、有効なYAMLを使用するほうがずっと良いでしょう。もちろんYAMLの

は拡張可能であり、そして、あなたの設定ファイルに「注文したマッピング」タイプを追加することからあなたを止めるものは何もありません。たとえば:

!omap setting1: 
    name: [item,item] 
    name1: text 
!omap anothersetting2: 
    name: [item,item] 
    !omap sub_setting: 
     name :[item,item] 

あなたが使っているどのyamlモジュールは言及しませんでした。そのようなモジュールは標準ライブラリにはなく、その名前のモジュールを提供する少なくとも2つのパッケージがPyPIのすぐ上にあります。しかし、私はそれが最も人気があることを知っているので、私はそれがピヤムだと推測するつもりです。

上記拡張はPyYAMLとして解析することが容易です。

{'anothersetting2': {'name': ['item', 'item'], 
    'sub_setting': 'name :[item,item]'}, 
'setting1': {'name': ['item', 'item'], 'name1': 'text'}} 

あなたは、これが得られます:代わりに、今

def omap_constructor(loader, node): 
    return loader.construct_pairs(node) 
yaml.add_constructor(u'!omap', omap_constructor) 

http://pyyaml.org/ticket/29を参照してください

(('anothersetting2', (('name', ['item', 'item']), 
    ('sub_setting', ('name, [item,item]'),))), 
('setting1', (('name', ['item', 'item']), ('name1', 'text')))) 

もちろん、これはあなたに、キーと値tuple Sのtupleを与えるが、あなたは簡単にconstruct_ordereddictを書くことができ、代わりにOrderedDictを得ることができます。また、入力と同様に出力する必要がある場合は、OrdereredDictオブジェクトを格納する代理人を!omapと書くこともできます。

PyYAMLをフックしてデフォルトのマッピングにdictの代わりにOrderedDictを使用する場合は、すでにパーサーオブジェクトで直接作業している場合はかなり簡単ですが、それに固執するのが難しい場合は高水準の便利なメソッド。幸運にも、上記リンクされたチケットには、使用できる実装があります。あなたが本当のYAMLをもう使用していないことを覚えておいてください。しかし、ファイルを扱う他のソフトウェアが破損する可能性があります。

0

私が聞いた最後、PyYAMLとは、これをサポートしていませんでした。

+0

これは実際には機能しません。まず、YAML文書は辞書である必要はありません。第二に、 'OrderedDict'で始めると、すべてのサブディクショナリは' dict'になります。だからあなたが本当に必要とするのは、 'dict'の代わりに使う別のコンストラクタを受け入れるように変更することです(そして、理想的には、それが使用する各コンストラクタごとに1つ、他のものはしばしば役に立たないでしょう)。 – abarnert

3

これではruaml.yamlを使用できるようになりました。 https://pypi.python.org/pypi/ruamel.yamlから

ruamel.yamlは、単一の特定のためにYAMLパーサ/コメント、SEQ /マップフロースタイルの往復 保存をサポートしてエミッタ、およびマッピングキーの順序

0

です順序付けられた辞書であることが知られているアイテムは、リストのアイテムを作成し、コレクションを使用するだけです.OrderedDict:

setting1: 
    - name: [item,item] 
    - name1: text 
anothersetting2: 
    - name: [item,item] 
    - sub_setting: 
     name :[item,item] 

import collections 
import yaml 
fh = open('setting.txt', 'r') 
setting_list = yaml.load(fh) 

setting1 = collections.OrderedDict(list(x.items())[0] for x in setting_list['setting1']) 
関連する問題