2014-01-10 80 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作为另一个问题的答案。