首页 > 解决方案 > 在python中一次解析一个yaml列表元素

问题描述

python中是否有一个yaml库可以根据需要一次读取输入文件一个条目,而不是解析整个文件?我有一个以列表为根节点的长文件。如果我试图找到满足某个属性的第一个元素,我可能不需要读取和解析整个文件,并且可以更快地获得结果。

标签: pythonyaml

解决方案


您可以使用 PyYAML 的低级parse()API:

import yaml

for event in yaml.parse(input):
    # process event

这些事件记录在这里

如果要将根级序列的每一项构造成原生 Python 值,则需要使用ComposerConstructor类。Composer读取事件并将它们转换为节点,从节点Constructor构建 Python 值。这对应于 YAML 规范中定义的加载过程:

现在 PyYAMLComposer期望函数get_event,check_eventpeek_event存在于 上self,但没有实现它们。它们由Parser. 因此,为了有一个有效的 YAML 加载链,PyYAML 稍后会:

class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
  def __init__(self, stream):
    Reader.__init__(self, stream)
    Scanner.__init__(self)
    Parser.__init__(self)
    Composer.__init__(self)
    Constructor.__init__(self)
    Resolver.__init__(self)

对您而言,这意味着您需要一个Loader对象并使用ParserAPI 来处理顶级事件,以及使用ComposerAPIConstructor来加载顶级序列中的每个项目。

这是一些可以帮助您入门的代码:

import yaml

input = """
- "A": 1
- "B": 2
- foo
- 1
"""

loader = yaml.SafeLoader(input)

# check proper stream start (should never fail)
assert loader.check_event(yaml.StreamStartEvent)
loader.get_event()
assert loader.check_event(yaml.DocumentStartEvent)
loader.get_event()

# assume the root element is a sequence
assert loader.check_event(yaml.SequenceStartEvent)
loader.get_event()

# now while the next event does not end the sequence, process each item
while not loader.check_event(yaml.SequenceEndEvent):
    # compose current item to a node as if it was the root node
    node = loader.compose_node(None, None)
    # construct a native Python value with the node.
    # we set deep=True for complete processing of all the node's children
    value = loader.construct_object(node, True)
    print(value)

# assume document ends and no further documents are in stream
loader.get_event()
assert loader.check_event(yaml.DocumentEndEvent)
loader.get_event()
assert loader.check_event(yaml.StreamEndEvent)

请注意,如果 YAML 文档中有锚点和别名,您可能会遇到问题。


推荐阅读