我有一个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
?
答案 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协议的情况下完成的,因为OrderedDict
是list
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,其中键的顺序将符合预期。