【问题标题】:YAML list -> Python generator?YAML 列表-> Python 生成器?
【发布时间】:2015-07-06 16:25:56
【问题描述】:

我想知道是否有一种简单的方法可以使用 PyYAML 将包含项目列表的 YAML 文档解析为 python 生成器。

例如,给定文件

# foobar.yaml
---
- foo: ["bar", "baz", "bah"]
  something_else: blah
- bar: yet_another_thing

我希望能够做类似的事情

for item in yaml.load_as_generator(open('foobar.yaml')): # does not exist
    print(str(item))

我知道有 yaml.load_all,可以实现类似的功能,但是你需要把每条记录当作自己的文档。我问的原因是因为我有一些非常大的文件,我想将它们转换为 YAML,然后以低内存占用进行解析。

我查看了 PyYAML 事件 API,但它吓到了我 =)

【问题讨论】:

    标签: python event-handling yaml pyyaml


    【解决方案1】:

    我可以理解事件 API 让您感到害怕,它只会给您带来这么多。首先,您需要跟踪深度(因为您有顶级复杂序列项目,以及“bar”、“baz”等。 而且,正确剪切低级序列事件元素后,您必须将它们输入作曲家以创建节点(并最终创建 Python 对象),这也不是微不足道的。

    但由于 YAML 使用缩进,即使对于跨多行的标量,您也可以使用一个简单的基于行的解析器,它可以识别每个序列元素的开始位置,并一次将其输入到普通的 load() 函数中:

    #/usr/bin/env python
    
    import ruamel.yaml
    
    def list_elements(fp, depth=0):
        buffer = None
        in_header = True
        list_element_match = ' ' * depth + '- '
        for line in fp:
            if line.startswith('---'):
                in_header = False
                continue
            if in_header:
                continue
            if line.startswith(list_element_match):
                if buffer is None:
                    buffer = line
                    continue
                yield ruamel.yaml.load(buffer)[0]
                buffer = line
                continue
            buffer += line
        if buffer:
           yield ruamel.yaml.load(buffer)[0]
    
    
    with open("foobar.yaml") as fp:
       for element in list_elements(fp):
           print(str(element))
    

    导致:

    {'something_else': 'blah', 'foo': ['bar', 'baz', 'bah']}
    {'bar': 'yet_another_thing'}
    

    我在这里使用了 PyYAML 的增强版 ruamel.yaml(我是其中的作者),但 PyYAML 应该以相同的方式工作。

    【讨论】:

    • 真是太好了——谢谢!我还将检查 ruamel.yaml 的其他功能 =)
    猜你喜欢
    • 2016-04-14
    • 2015-01-16
    • 1970-01-01
    • 2016-10-04
    • 2018-03-26
    • 2020-07-18
    • 2014-08-28
    • 2017-06-10
    • 2021-02-25
    相关资源
    最近更新 更多