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中進行了大量數據傳遞,並且每個記錄都必須使用密鑰進行簽名,無論何時使用字符/散列,無限期的順序都會阻止統一的簽名。
Python的字典是無序的。 –
這與YAML沒什麼關係,但是用Python:嘗試在控制檯輸入'{'3':5,'1':3}'。 Python字典是無序的。所以,如果你想保持順序(無論是元組列表,還是'collections.OrderedDict',或其他東西),你的第一步就是決定如何改變你的數據結構。 – DSM
@DSM謝謝。但它增加了!python/objectapply:collections.OrderedDict到我的YAML文件 – Samuel