用于python列表的Yaml转储使用内联格式而不是hypen + space

时间:2016-03-14 04:02:46

标签: python yaml pyyaml

我有一个python有序词典,如

from collections import OrderedDict 
a = OrderedDict()
a['name'] = 'hello'
a['msgs'] = ['hello', 'world']

我正在将其转换为YAML语法,

import yaml
with open("b.yaml", 'w') as stream:
  stream.write(yaml.dump(a))

打印,

!!python/object/apply:collections.OrderedDict
- - [name, hello]
  - - msgs
    - [hello, world]

然而,我期望更简单的YAML格式,

name : hello
msgs:
   - hello
   - world

如何强制YAML使用hypen + space表示法打印列表项而不是[a,b,c,d]表示法的JSON?

为什么PyYAML将Ordered dict项目打印为[name, hello]而不是name : hello

2 个答案:

答案 0 :(得分:3)

你的问题让一些事情混淆不清。从您的初始示例开始,您需要使用显式编码将a = {...}投射到OrderedDict。把它放在一边,这是你期望的输出:

>>> a = {
...   "name" : 'hello',
...   "msgs" : ['hello', 'world']
... }
>>> print(yaml.dump(a))
msgs: [hello, world]
name: hello

这并不是你想要的。如果您在此问题上专门阅读了FAQ,您会发现将default_flow_style传递给dump会产生您想要的结果

>>> print(yaml.dump(a, default_flow_style=False))
msgs:
- hello
- world
name: hello

至于OrderedDict出现的原因,文档中的YAML tags and Python types部分对此进行了讨论。简而言之,这是在考虑Python的pickle协议的情况下完成的,因为OrderedDictlist s内部(list s是有序的; dict是按定义无序),它获得类似列表的表示。

答案 1 :(得分:2)

如果您没有阅读YAML规范,您可能希望订购YAML文件中的映射,因为YAML文件中的文本表示是有序的。不幸的是,这个直观的假设是错误的,YAML 1.2明确指出这[应该被解释为] 无序的 键:值对的集合。

这当然使得使用diff之类的工具比较YAML文件几乎是不可能的,如果你使用映射并加载/更改/转储它们,并且将这些类型的文件检入修订控制系统会导致虚假的额外修订语义相同,但不是语法上的。

我也出于其他原因开始改进PyYAML(YAML 1.2兼容性,而不是旧的1.1规范,保留注释,修复错误),但ruamel.yaml如果你使用它{{{3}}也保留了作为映射的排序1}}:

round_trip_dump

为您提供包含内容的文件import ruamel.yaml from ruamel.yaml.comments import CommentedMap as OrderedDict a = OrderedDict() a['name'] = 'hello' a['msgs'] = ['hello', 'world'] with open("b.yaml", 'w') as stream: ruamel.yaml.round_trip_dump(a, stream, indent=5, block_seq_indent=3)

b.yaml

完全您的期望。

请注意我已将流传递到name : hello msgs: - hello - world ,如果您使用PyYAML,您也应该这样做,因为它更有效。
您需要使用round_trip_dump,它只是OrderedDict / ordereddict的一个薄包装器,允许保留注释等。
默认CommentedMap为2,indent为0.

如果您使用block_seq_indent加载文件,则会再次获得一个CommentedMap,其中键的顺序将符合预期。