在没有循环的方法中产生

yield in method without loop

我正在研究 ruamel.yaml API 使用源代码并找到 this strange pattern in code:

    def construct_yaml_map(self, node):
        # type: (Any) -> Any
        data = CommentedMap()
        data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
        yield data
        self.construct_mapping(node, data, deep=True)
        self.set_collection_style(data, node)

这就使得有必要编写这样的代码 (inspired by the code in another place)

generator = yaml.constructor.construct_yaml_map(mapping_node)
# method does not run, only returns generator

data = next(generator)
# method executes until yield data (empty CommentedMap)

for _dummy in generator:
  # on first iteration method continues until end
  # no second iteration
  pass

# or alternative expression
#try:
#  next(generator)
#except StopIteration:
#  pass

# now data is filled

在没有任何循环的方法中间使用这个 yield 有什么用?

Python 允许您创建递归数据结构,与 许多其他流媒体格式,YAML 允许您转储这些

import sys
import ruamel.yaml

data = dict(a=1)
data['b'] = data

yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)

给出:

&id001
a: 1
b: *id001

其中&id001是YAML语言中的一个锚点,被*id001引用,称为别名。

我不知道有什么方法可以在不使用多个语句的情况下在 Python 中创建 data。你需要 对象(或其 id)能够将其添加到自身。 YAML 加载器有类似的问题: 当它解析和构造一个组合(映射或序列)时,它会收集所有 children (key/value pairs resp. elements) 然后构造复合体。所以当复合 在 YAML 中(通过别名)引用自身,锚点的查找需要提供一个真实的,尽管 不完整、构造的 Python 对象(字典、列表,如果是标记对象,则可能是实例 一些 class).

这就是使用创建复合材料的两步过程的原因:您创建一个空对象,它 你交回去,所以如果有必要,可以在 anchor/alias table 中进行参考, 然后在代码的 post yield 部分填写它。

复合材料本身不需要在其中一个中有别名 他们的价值观或元素,但如果他们没有锚,他们可以 在一步过程中构建。但这会导致 不同的构造函数和调用 construct_yaml_map() 的代码 了解这些不同构造的对象。问题 转移,但不会消失,就像你可以创建递归 Python 不同,但仍然需要多个语句。

顺便说一句,这不是 ruamel.yaml 具体的。这段代码在 PyYAML 代码中,而且 AFAIK 仍然如此 ruamel.yaml 的来源。