如何加载 pyYAML 文件并使用属性而不是使用字典表示法访问它?
Posted
技术标签:
【中文标题】如何加载 pyYAML 文件并使用属性而不是使用字典表示法访问它?【英文标题】:How to load a pyYAML file and access it using attributes instead of using the dictionary notation? 【发布时间】:2012-06-18 10:21:45 【问题描述】:我有一个 YAML 配置,如下所示:
config:
- id: foo
- name: bar
content:
- run: xxx
- remove: yyy
我正在使用 Python YAML 模块来加载它,但我想以更好的方式访问它,例如:
stream = open(filename)
config = load(stream, Loader=Loader)
print(config['content'])
我想要的是能够做到:print(config.content)
。
【问题讨论】:
***.com/questions/2352181/… 的副本 @Justin:这不是这个问题的重复,因为你可以简单地修补 YAML 加载器来创建你想要的任何类的对象,而不是dict
的实例。
【参考方案1】:
执行此操作的最简单方法可能是覆盖 tag:yaml.org,2002:map
的 YAML 构造函数,以便它返回自定义字典类而不是普通字典。
import yaml
class AttrDict(object):
def __init__(self, attr):
self._attr = attr
def __getattr__(self, attr):
try:
return self._attr[attr]
except KeyError:
raise AttributeError
def construct_map(self, node):
# WARNING: This is copy/pasted without understanding!
d =
yield AttrDict(d)
d.update(self.construct_mapping(node))
# WARNING: We are monkey patching PyYAML, and this will affect other clients!
yaml.add_constructor('tag:yaml.org,2002:map', construct_map)
YAML = """
config:
- id: foo
- name: bar
content:
- run: xxx
- remove: yyy
"""
obj = yaml.load(YAML)
print(obj.config[0].id) # prints foo
请注意,如果它希望一切都以正常的 Python 方式工作,这将破坏使用 YAML 的进程中的所有其他内容。您可以使用自定义加载器,但我个人认为 PyYAML 文档有点迷宫,而且副作用似乎是全局性的,并且通常具有传染性,而不是例外。
您已被警告。
作为替代方案,如果您的架构相对静态,您可以编写自己的类并反序列化为那些(例如,class Config
与 id
和 name
属性)。但是,这可能不值得花费额外的代码。
【讨论】:
将其简化并改进为gist.github.com/ktaragorn/9cf6d368378b0f65a3a0。没有猴子补丁,它也以嵌套方式工作 @KarthikT:嵌套在数组中的字典失败。 我什至没有考虑过那个用例..当您考虑配置文件时,这种情况经常发生吗? 是的,我认为它会经常发生。例如,在配置 Web 服务器时,您会有一个不同虚拟主机的列表。【参考方案2】:您可以使用以下类将对象表示法与字典一起使用,如this 答案中所述:
class DictAsMember(dict):
def __getattr__(self, name):
value = self[name]
if isinstance(value, dict):
value = DictAsMember(value)
return value
这个类在行动:
>>> my_dict = DictAsMember(one=1, two=2)
>>> my_dict
'two': 2, 'one': 1
>>> my_dict.two
2
编辑这可以递归地使用子词典,例如:
>>> my_dict = DictAsMember(one=1, two=2, subdict=dict(three=3, four=4))
>>> my_dict.one
1
>>> my_dict.subdict
'four': 4, 'three': 3
>>> my_dict.subdict.four
4
【讨论】:
我认为这不能递归地工作,因为您可以想象配置树中的其他条目会重复同样的问题。 如果我明白你的意思,这确实是递归的。我的编辑是否回答了您的观点? 为什么这个(最简单的答案)没有被投票一百万次?有几十个类似/重复的问题以如此复杂的方式回答这个问题!以上是关于如何加载 pyYAML 文件并使用属性而不是使用字典表示法访问它?的主要内容,如果未能解决你的问题,请参考以下文章