在 Python3 中使用 ruamel.yaml 解析 Yaml 嵌套配置

Parsing Yaml nested configuration with ruamel.yaml in Python3

当使用 Python 包 ruamel.yaml 解析 YAML 配置文件时,我需要考虑到在同一个 YAML 文件中可以用两种不同的样式描述嵌套:

  1. 使用换行和缩进
  2. 使用点 (.)

简化示例:

运行 repl.it snippet

logging.yml

# 1. by using new line and indents
logging: 
  file: 
    name: app.log
# 2. by using dots (.)
logging.file.path: /logs

main.py

#!/usr/bin/env python3

import ruamel.yaml as yaml

with open('logging.yml', 'r') as file:
  data = yaml.safe_load(file)
print(data)

实际输出:

{
  'logging': {
    'file': {
      'name': 'app.log'
    }
  },
  'logging.file.path': '/logs'
}

是否可以以某种方式配置 ruamel.yaml 以便我可以将 path 属性 嵌套在 logging->file 中,如下所述,以便我可以轻松访问属性然后? :

{
  'logging': {
    'file': {
      'name': 'app.log',
      'path': '/logs'
    }
  }
}

不,不可能按照你的方式配置ruamel.yaml 想。我什至认为尝试创建构造函数是个坏主意 那会在加载过程中即时执行您想要的操作,例如意味着你 在解析映射时需要考虑到 这是键 file 的值,一个 python 字典已经可以 由于分裂 logging.file.path.

而存在

我建议您 post-处理您的 data:

from pprint import pprint
import ruamel.yaml

yaml_str = """\
logging: 
  file: 
    name: app.log
logging.file.path: /logs
"""


yaml = ruamel.yaml.YAML(typ='safe')
data = yaml.load(yaml_str)
for k in list(data.keys()):
    if not '.' in k:
        continue
    keys = k.split('.')
    d = data
    while len(keys) > 1:
        d = d.setdefault(keys.pop(0), {})
    d[keys[0]] = data.pop(k)
pprint(data, width=-1)

给出:

{'logging': {'file': {'name': 'app.log',
                      'path': '/logs'}}}

如有必要,您可以递归地执行此操作,以防您有密钥 根级别不存在的点。