2014-01-10 108 views
2

我用PyYaml來輸出YAML文件。但它重新排序我的項目。像以下python的YAML輸出格式

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

我想得到"{'3': 5, '1': 3}\n"。我可以做那件事嗎

PS。我試過collections.OrderedDict。它的輸出不好。 Like following

>>> 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" 
+0

Python的字典是無序的。 –

+2

這與YAML沒什麼關係,但是用Python:嘗試在控制檯輸入'{'3':5,'1':3}'。 Python字典是無序的。所以,如果你想保持順序(無論是元組列表,還是'collections.OrderedDict',或其他東西),你的第一步就是決定如何改變你的數據結構。 – DSM

+0

@DSM謝謝。但它增加了!python/objectapply:collections.OrderedDict到我的YAML文件 – Samuel

回答

4

TL; DR:解決方法是在兩行中評論爲「看這裏!」它可能在程序中處理YAML作爲字符串,並且如果您接受輸出將是列表的列表,則可以在存儲的文件/文本中進行排序。

如果你不介意像!! python/ordered_dict或!! omap等可怕醜陋的顯式類型拋棄你的文件,那麼你也可以走這條路線。我的投票結果是!! omap,但我不確定有多少工具/庫支持它(儘管我確信更少的工具支持!! python/ordered_dict)。最終,你正在處理兩組獨立的數據:字典本身,以及定義密鑰排序的元數據。 (在YAML中沒有!! python/ordered_dict或!! omap亂七八糟的地方,強制使用有序的字典有半神奇的方式,但它們很脆弱,與字典的定義相矛盾,並且可能會因爲底層的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') 

的文件創建這樣的:

ordered.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作爲初始輸入(yay!),並且將從不漂亮,有序的YAML轉換爲漂亮的,仍然有序的字典式YAML的腳本編寫非常簡單(我將其留作練習) 。

如果您有要保留的鍵的順序,請將其寫入有序列表/元組中。使用該列表生成列表的有序列表(不是元組列表,因爲您將在YAML中獲得!! python/tuple類型,並且很糟糕)。轉儲到YAML。要重新讀取它,請按正常方式讀取它,然後將該結構傳遞給dict(),然後返回到您開始使用的原始字典。如果你有一個需要保留順序的嵌套結構(這在代碼中比在散文中解釋更容易 - 這是你可能已經知道的東西),你可能必須遞歸地下降結構。

在這個例子中,我想先在文件中有一個項目'name',然後是'version'數字元素,然後是'add-ons'。通常PyYAML在調用dump()時以字母數字順序命令字典密鑰,但這不可靠,因爲這可能會在將來發生變化,並且YAML標準中沒有任何內容需要這樣做,所以我不能保證不同的YAML實用程序會這樣做。 'add-ons'出現在'name'之前,所以我有一個訂購問題。所以我定義了我的訂單,然後打包一個有序列表,然後轉儲它。

您要求訂購的東西本質上是無序的。字典是一個哈希表,內部專門用於搜索速度。這個順序是你不應該混淆的,因爲如果明天發現更快的實現字典的方式,運行時需要實現它,而不會破壞所有依賴字典作爲散列表有用抽象的代碼。以同樣的方式,YAML不是標記語言(畢竟它最初代表「Yaml不是標記語言」),它是一種數據格式。差異很重要。一些數據被排序,如元組和列表;有些並不像鍵值對那樣(與哈希表略有不同,但在概念上相似)。

我使用這種解決方案的遞歸版本來保證不同YAML實現的YAML輸出,而不是爲了人類的可讀性,但是因爲我在YAML中進行了大量數據傳遞,並且每個記錄都必須使用密鑰進行簽名,無論何時使用字符/散列,無限期的順序都會阻止統一的簽名。

2

YAML映射無序,Python字典也是無序的。在文件 中讀取並保持排序的官方方式是使用!!omap,但那些在PyYAML中轉換爲元組並且不像dict/ordereddict/OrderedDict那樣容易更新。

如果你已經有一個yaml文件,你閱讀和更新,你可以使用我的ruamel.yaml圖書館讀取映射時,在往返模式下使用ordereddict並寫出它們作爲正常映射(它也保留註釋) 。

使用的example作爲另一個問題的答案。