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