YAML 列表 -> Python 生成器?

YAML list -> Python generator?

我想知道是否有一种简单的方法可以使用 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 但它吓到我了 =)

我能理解事件 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 应该以相同的方式工作。