如何将YAML文件解析为Python对象?

131 投票
4 回答
233307 浏览
提问于 2025-04-16 22:28

如何将YAML文件解析成Python对象?

比如,这个YAML文件:

Person:
  name: XYZ

可以转换成这个Python类:

class Person(yaml.YAMLObject):
  yaml_tag = 'Person'

  def __init__(self, name):
    self.name = name

顺便说一下,我是用的PyYAML这个库。

4 个回答

5

我写了一个使用 命名元组 的实现,我觉得这个方法挺不错的,因为它比较易读。它还可以处理字典嵌套的情况。下面是解析器的代码:

from collections import namedtuple


class Dict2ObjParser:
    def __init__(self, nested_dict):
        self.nested_dict = nested_dict

    def parse(self):
        nested_dict = self.nested_dict
        if (obj_type := type(nested_dict)) is not dict:
            raise TypeError(f"Expected 'dict' but found '{obj_type}'")
        return self._transform_to_named_tuples("root", nested_dict)

    def _transform_to_named_tuples(self, tuple_name, possibly_nested_obj):
        if type(possibly_nested_obj) is dict:
            named_tuple_def = namedtuple(tuple_name, possibly_nested_obj.keys())
            transformed_value = named_tuple_def(
                *[
                    self._transform_to_named_tuples(key, value)
                    for key, value in possibly_nested_obj.items()
                ]
            )
        elif type(possibly_nested_obj) is list:
            transformed_value = [
                self._transform_to_named_tuples(f"{tuple_name}_{i}", possibly_nested_obj[i])
                for i in range(len(possibly_nested_obj))
            ]
        else:
            transformed_value = possibly_nested_obj

        return transformed_value

我用以下代码测试了一些基本情况:

x = Dict2ObjParser({
    "a": {
        "b": 123,
        "c": "Hello, World!"
    },
    "d": [
        1,
        2,
        3
    ],
    "e": [
        {
            "f": "",
            "g": None
        },
        {
            "f": "Foo",
            "g": "Bar"
        },
        {
            "h": "Hi!",
            "i": None
        }
    ],
    "j": 456,
    "k": None
}).parse()

print(x)

它输出的结果是: root(a=a(b=123, c='Hello, World!'), d=[1, 2, 3], e=[e_0(f='', g=None), e_1(f='Foo', g='Bar'), e_2(h='Hi!', i=None)], j=456, k=None)

稍微格式化一下后,看起来像这样:

root(
    a=a(
        b=123,
        c='Hello, World!'
    ),
    d=[1, 2, 3],
    e=[
        e_0(
            f='',
            g=None
        ),
        e_1(
            f='Foo',
            g='Bar'
        ),
        e_2(
            h='Hi!',
            i=None
        )
    ],
    j=456,
    k=None
)

我可以像访问其他对象一样访问嵌套的字段:

print(x.a.b)  # Prints: 123

在你的情况下,代码最终看起来会是这样的:

import yaml


with open(file_path, "r") as stream:
    nested_dict = yaml.safe_load(stream)
    nested_objt = Dict2ObjParser(nested_dict).parse()

希望这对你有帮助!

19

来自 http://pyyaml.org/wiki/PyYAMLDocumentation:

add_path_resolver(tag, path, kind) 是一个用来添加基于路径的隐式标签解析器的函数。这里的“路径”指的是一系列的键,这些键组合在一起可以找到表示图中的一个节点。路径中的元素可以是字符串、整数,或者是 None(表示没有值)。而节点的类型可以是字符串、列表、字典,或者也是 None。

#!/usr/bin/env python
import yaml

class Person(yaml.YAMLObject):
  yaml_tag = '!person'

  def __init__(self, name):
    self.name = name

yaml.add_path_resolver('!person', ['Person'], dict)

data = yaml.load("""
Person:
  name: XYZ
""")

print data
# {'Person': <__main__.Person object at 0x7f2b251ceb10>}

print data['Person'].name
# XYZ
219

如果你的YAML文件长这样:

# tree format
treeroot:
    branch1:
        name: Node 1
        branch1-1:
            name: Node 1-1
    branch2:
        name: Node 2
        branch2-1:
            name: Node 2-1

而你已经像这样安装了 PyYAML

pip install PyYAML

然后你的Python代码看起来是这样的:

import yaml
with open('tree.yaml') as f:
    # use safe_load instead load
    dataMap = yaml.safe_load(f)

现在,变量 dataMap 里面包含了一个字典,里面有树的数据。如果你用PrettyPrint打印 dataMap,你会看到类似这样的内容:

{
    'treeroot': {
        'branch1': {
            'branch1-1': {
                'name': 'Node 1-1'
            },
            'name': 'Node 1'
        },
        'branch2': {
            'branch2-1': {
                'name': 'Node 2-1'
            },
            'name': 'Node 2'
        }
    }
}

所以,现在我们已经看到如何把数据放进我们的Python程序里。保存数据同样简单:

with open('newtree.yaml', "w") as f:
    yaml.dump(dataMap, f)

你有一个字典,现在你需要把它转换成一个Python对象:

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

然后你可以使用:

>>> args = your YAML dictionary
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s...

并参考 "将Python字典转换为对象"。

想了解更多信息,你可以查看 pyyaml.org这个链接

撰写回答