python列表的Yaml转储使用内联格式而不是连字符+空格



我有一个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 将有序字典项目打印为[name, hello]而不是name : hello

你的问题混淆了几件事。 从初始示例开始,您需要显式编码才能将a = {...}转换为OrderedDict。 撇开这一点不谈,这是您的预期输出:

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

这不是你想要的。 如果您专门阅读有关此问题的常见问题解答,您会发现将default_flow_style传递给dump将产生您想要的结果

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

至于为什么OrderedDict这样出现,这在文档中的 YAML 标签和 Python 类型部分中进行了讨论。 简而言之,这是考虑到 Python 的 pickle 协议,并且由于OrderedDict在内部listlist s 是有序的; dict根据定义是无序的),它得到类似列表的表示形式。

如果不阅读 YAML 规范,则期望对 YAML 文件中的映射进行排序,因为 YAML 文件中的文本表示形式是有序的。不幸的是,这种直观的假设是错误的,YAML 1.2明确指出这[应该被解释为]一组无序的键:值对

当然,如果您使用映射并加载/更改/转储它们,则使用诸如diff之类的工具比较 YAML 文件几乎是不可能的,并且使此类文件签入版本控制系统会导致语义相同但不在语法上的虚假额外修订。

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

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

这正是你所期望的。

请注意,我将流传递给round_trip_dump,如果您使用 PyYAML,您也应该这样做,因为它更有效率。
您需要使用 CommentedMap ,它只是 OrderedDict/ordereddict 的薄包装器,允许保留注释等。
默认indent为 2,block_seq_indent为 0。

如果使用 round_trip_dump 加载文件,您将再次获得一个 CommentedMap,其中键的顺序将按预期排列。

最新更新