如何将YAML文件解析为Python对象?
如何将YAML文件解析成Python对象?
比如,这个YAML文件:
Person:
name: XYZ
可以转换成这个Python类:
class Person(yaml.YAMLObject):
yaml_tag = 'Person'
def __init__(self, name):
self.name = name
顺便说一下,我是用的PyYAML这个库。
4 个回答
我写了一个使用 命名元组 的实现,我觉得这个方法挺不错的,因为它比较易读。它还可以处理字典嵌套的情况。下面是解析器的代码:
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()
希望这对你有帮助!
来自 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
如果你的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 和 这个链接。