我有一个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)
我有一个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)
您可以使用使用以下类词典,如中所讨论的对象符号这个答案:
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
要做到这一点最简单的方法可能是覆盖在YAML构造tag:yaml.org,2002:map
,以便返回而不是一个普通的字典中的自定义词典类。
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
请注意,这将打破一切在使用YAML,如果它希望一切工作正常的Python的方式处理事情。 您可以使用自定义的加载,但我个人找PyYAML文档有点迷路,它似乎是副作用是全球性和传染性的规则,而不是例外。
你被警告了。
作为替代方案,如果你的模式是相对静态的,你可以编写自己的类和反序列化到那些(如class Config
与id
和name
属性)。 它可能不会是值得的额外的代码的成本,但是。