我使用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"
答案 0 :(得分:4)
TL; DR:解决方案在两行评论"在这里查看!"如果您接受输出将是列表列表,那么 可以在程序中处理YAML,并且可以在存储的文件/文本中进行排序。
如果你不介意可怕的丑陋的显式类型,比如!! python / ordered_dict或!! omap乱扔你的文件,那么你也可以去那条路线。我的投票是!! omap,但我不确定有多少工具/库支持它(我很确定更少的工具支持!! python / ordered_dict,但是)。最终,您正在处理两组独立的数据:dict本身,以及定义键的顺序的元数据。
(在YAML中有一些半神奇的方法来强制有序的dict,而没有!! 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转换为漂亮的,仍然有序的,dict风格的YAML的转换脚本是直截了当的(我留给你作为练习)
如果您要保留要保留的密钥的顺序,请将其写入有序列表/元组。使用该列表生成一个有序的列表列表(不是元组列表,但是因为你在YAML中得到了!! python / tuple类型,而且很糟糕)。转发给YAML。要在正常情况下阅读它,然后将该结构传递给dict(),然后返回到您开始使用的原始字典。如果你有一个需要保留其顺序的嵌套结构,你可能必须递归地下降结构(这在代码中比在散文中更容易解释 - 这是你可能已经知道的东西)。
在这个例子中,我希望有一个项目名称'首先在文件中,然后'版本'数字元素,然后'附加组件'。通常PyYAML在调用dump()时会按字母数字顺序对字典键进行排序,但这不可靠,因为将来可能会发生变化,而YAML标准中没有任何内容需要这样做,所以我无法保证不同YAML实用程序将以这种方式执行操作。 '附加'来之前的名字',所以我有一个订购问题。所以我定义了我的订单,然后打包一个有序的列表列表,然后转储它。
您要求订购本身无序的订单。字典是一个哈希表,内部专门用于搜索速度。这个顺序是你不应该弄乱的东西,因为如果明天发现更快的实现字典的方法,那么运行时需要实现它而不会破坏依赖于字典作为一个有用的抽象的每个人的代码哈希表。
同样地,YAML不是标记语言(毕竟,它最初代表" Yaml Ain是标记语言"),它是一种数据格式。差异很重要。一些数据是有序的,如元组和列表;有些不是键值对(与哈希表略有不同,但在概念上类似)。
我使用这种解决方案的递归版本来保证不同YAML实现的YAML输出,不是为了人类的可读性,而是因为我在YAML中传递了大量数据,并且每条记录都必须用密钥签名,并且无论何时使用dicts / hashes,无限期命令都会阻止统一签名。
答案 1 :(得分:2)
YAML映射是无序的,Python dicts也是如此。阅读文件的官方方式
并保持顺序是使用!!omap
,但那些在PyYAML中转换为元组,并且不像dict
/ ordereddict
/ OrderedDict
那样容易更新。
如果您已经读入并更新了yaml文件,则可以使用我的ruamel.yaml
库在读取映射时读取映射作为ordereddict并将其作为普通映射写出(也可以保护者评论)。
使用了example作为另一个问题的答案。