使配置 yaml 对于嵌套列表更具可读性

make config yaml more readable for nested list

我有这个 YAML 示例:

people:
      name: abc
      address: '55 Oxford Street, San Jose 95134. CA'
      occupation: 'Travel Blogger'
      Hobby: 'Travelling'
      additional_interests: []
      other_info: [['gender', 'male'], ['no_of_cars', 'three'],
             ['hair_color', 'black'], ['eye_color', 'brown']]

我想以输出 yaml 应该是这样的方式呈现它:

people:
      name: abc
      address: '55 Oxford Street, San Jose 95134. CA'
      occupation: 'Travel Blogger'
      Hobby: 'Travelling'
      additional_interests: []
      other_info: [
          ['gender', 'male'], 
          ['no_of_cars', 'three'],
          ['hair_color', 'black'], 
          ['eye_color', 'brown']
      ]

我正在使用以下代码:

from ruamel.yaml import YAML as Ruamel
from pathlib import Path
yaml = Ruamel(typ='rt')
config_file = Path('/Users/test_config.yaml')
configs = yaml.load(config_file.read_text())
component_file="xyz.txt"
with open(component_file, 'w') as component:
    for key, value in configs.items():
        yaml.default_flow_style=None
        yaml.dump({key: value}, component)

这里的想法是将现有的 YAML 文件转换为更易于阅读的格式。任何指示如何实现我正在寻找的格式 - 对于 YAML 中的嵌套列表?

如果使用,只需设置一次yaml.default_flow_style。但在 往返模式只影响新创建的 dicts 和 lists。所有加载的数据结构都明确设置和保留了 block/flow 样式,并且不受 .default_flow_style 的影响。 以增量方式将 YAML 文档转储到文件几乎总是一个坏主意,您可以通过这种方式轻松创建 invalid/unloadable YAML 文档。

如文档所述,ruamel.yaml 明确尝试保留 block 样式, 相反(大部分)规范化流式。 一个很好的测试,看看你是否可以通过往返预期的 YAML 格式来实现你想要的输出 查看 ruamel.yaml 是否可以重新生成您的格式(以及它是否检查节点 如果您想从头开始创建它们,它们的特殊属性)。

在您的情况下,您会注意到 ruamel.yaml 没有专门处理这些嵌套的流式列表 并将它们标准化为不需要的样本格式。

如果嵌套序列的元素之间有注释,您会注意到 ruamel.yaml目前无法正确处理这些。他们不会迷路,但他们 插入到他们自己的一行中,这很好地表明试图插入空行 外部序列元素之间的注释也会产生额外的换行符。

我的主要建议是不要嵌套流式序列。

import sys
import ruamel.yaml

yaml_str = """\
people:
      name: abc
      address: '55 Oxford Street, San Jose 95134. CA'
      occupation: 'Travel Blogger'
      Hobby: 'Travelling'
      additional_interests: []
      other_info: [['gender', 'male'], ['no_of_cars', 'three'],
             ['hair_color', 'black'], ['eye_color', 'brown']]
"""

def no_nested_flow_style_seq(d):
    done = False
    if isinstance(d, dict):
        for k, v in d.items():
            no_nested_flow_style_seq(v)  # you can have sequences as keys in YAML, but it is rare
    elif isinstance(d, list):
        for elem in d:
            if not done and isinstance(elem, list):
                done = True
                d.fa.set_block_style()
            no_nested_flow_style_seq(elem)


yaml = ruamel.yaml.YAML()
# yaml.preserve_quotes = True
data = yaml.load(yaml_str)
no_nested_flow_style_seq(data)
yaml.dump(data, sys.stdout)

给出:

people:
  name: abc
  address: 55 Oxford Street, San Jose 95134. CA
  occupation: Travel Blogger
  Hobby: Travelling
  additional_interests: []
  other_info:
  - [gender, male]
  - [no_of_cars, three]
  - [hair_color, black]
  - [eye_color, brown]

为(块式)映射获取 6 个空格的缩进大小 序列,就像在您的示例输出中一样,您可以 转储前设置 yaml.indent(mapping=6, sequence=6, offset=4)。 然而,至于。人类的可读性,有一篇文章《程序缩进 和可理解性”(1983 年,Miara、Musselman、Navarro 和 Shneiderman (后者因 Nassi-Shneiderman 图成名) 在 ACM 的通讯中),这表明编程语言的可理解性 对于 2-4 个空格的缩进是最佳的,并且对于更高的值减少。 我不知道对人类可读数据格式的具体研究,等等 事情高度依赖于你的习惯,因此很难 凭个人经验判断,但 我建议不要为 YAML 使用如此大的缩进。

以上加载到与您的两个 YAML 样本相同的数据结构(对于所有 正常处理,格式化信息当然存储在某处,但肯定 其他程序,在往返模式下不使用 ruamel.yaml 看不出有什么区别)。 您可以设置 yaml.preserve_quotes = True,但在我看来您需要 如果人类处理引用的不一致(abc vs 'Travelling') 是看这些文件。设置也加载相同的数据结构。

如果数据格式可以改变,你应该考虑改变值 other_info 到字典列表:

  - gender: male
  - no_of_cars: three
  - hair_color: black
  - eye_color: brown

或标记标量的列表,这将允许您将它们加载到它们的拟合 class 实例中 (例如检查允许的标量值):

  - !Gender male
  - !No_Of_Cars three
  - !Hair_Color black
  - !Eye_Color brown