pyyaml 和 yaml 子级别

pyyaml and yaml sublevels

我正在尝试使用 PyYAML 将 YAML 文件解析为 python 对象

不过我在课程中提出了疑问

我有 YAML 文件

first_lvl:
   second_lvl:
       item_a:
          - value_a : "value aaa"
          - value_b : "value bbb"

我的 python 脚本读取 YAML 并将其加载到对象中

import yaml

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

with open(job_file.yml) as f:
    skeleton = yaml.full_load(f)

MyJob = Struct(**skeleton)

print(MyJob.first_lvl)

这很好,但仅适用于 YAML 的第一级。如果我想达到应该包含在对象中的 yaml 文件的子级值怎么样

像这样:

    print(MyJob.first_lvl.second_lvl) 

它可能与 PyYAML 模块无关,更多的是 python 处理对象的方式,但我还是迷路了

任何人都可以开灯吗?

在您的评论中,您表示希望只有一个 Struct 实例已加载。但是,如果您想访问该值 "value aaa" 通过写作 my_job.first_lvl.second_lvl.item_a.0.value_a,你不能这样做 通过提供 __getattr__ 方法,因为这会引发错误 说明 dict 对象没有 second_lvl 属性(它只是 有一个键 second_lvl)。 __getattr__ 永远不会被调用,因为, 在 Struct 实例上,属性查找不会失败。

你可以做的是提供一些方法 lookup 作为参数采用 "dotted" 字符串:

import ruamel.yaml

yaml_str = """\
first_lvl:
   second_lvl:
       item_a:
          - value_a : "value aaa"
          - value_b : "value bbb"
"""

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

    def lookup(self, s):
        def recurse(d, names):
            name = names[0]
            if isinstance(d, list):  # list indices cannot be strings
                name = int(name)                
            if len(names) > 1:
                return recurse(d[name], names[1:])
            return d[name]

        names = s.split('.')
        return recurse(getattr(self, names[0]), names[1:])

yaml = ruamel.yaml.YAML(typ='safe')
my_job = Struct(**yaml.load(yaml_str))

print(my_job.lookup("first_lvl.second_lvl.item_a.0.value_a"))

给出:

value aaa

显示了另一种扩展 在往返模式下使用 ruamel.yaml 时的默认数据结构。

如果你真的想写 my_job.first_lvl.second_lvl.item_a.0.value_a,没有引号,我 不认为有办法让每个级别都意识到看 上属性。这意味着扩展 Struct,所以 class 可以从映射 序列构造。那可以做到 在加载 YAML 之后,但 IMO 最好在构建 YAML 期间完成。