Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何加载pyYAML文件并使用属性而不是字典符号访问它?_Python_Yaml_Pyyaml - Fatal编程技术网

Python 如何加载pyYAML文件并使用属性而不是字典符号访问它?

Python 如何加载pyYAML文件并使用属性而不是字典符号访问它?,python,yaml,pyyaml,Python,Yaml,Pyyaml,我有一个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)

您可以使用以下类在字典中使用对象表示法,如答案中所述:

这类活动:

>>> 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

最简单的方法可能是覆盖
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
请注意,如果YAML希望所有内容都以正常的Python方式工作,那么这将破坏使用YAML的流程中的所有其他内容。您可以使用自定义加载程序,但我个人认为PyYAML文档有点复杂,而且副作用似乎是全局性的,并且作为一个规则而不是一个例外会传染

你已经被警告了


另一种选择是,如果您的模式是相对静态的,您可以编写自己的类并反序列化到这些类(例如,
class-Config
带有
id
name
属性)。然而,这可能不值得额外代码的花费。

Duplicate of@Justin:这不是这个问题的重复,因为您可以简单地修补YAML加载程序,以创建您想要的任何类的对象,而不是
dict
的实例。我认为这不会递归工作,你可以想象,同样的问题会在配置树中的其他条目上重复出现。如果我理解你的意思,这确实是递归的。我的编辑回答了你的观点吗?为什么这个(最简单的答案)没有被提升一百万次?有几十个类似/重复的问题以如此复杂的方式回答了这个问题!将其简化并改进为。没有monkeypatching,它以嵌套方式工作well@KarthikT:嵌套在数组中的字典失败。我甚至没有考虑过这个用例。。当您考虑配置文件时,这种情况经常发生吗?是的,我认为这种情况会经常发生。例如,在配置web服务器时,您会有一个不同虚拟主机的列表。
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