deep=True 在 pyyaml.Loader.construct_mapping 中做什么?

Jas*_*n S 6 pyyaml python-2.7

在网上搜索自定义构造函数的用法时,我看到如下内容:

def some_constructor(loader, node):
    value = loader.construct_mapping(node, deep=True)
    return SomeClass(value)
Run Code Online (Sandbox Code Playgroud)

其作用是什么deep=True我在pyyaml 文档中没有看到它。

看来我需要它;我有一个由 py​​yaml 表示器生成的 yaml 文件,它包括节点锚点和别名(如&id003*id003);如果没有,deep=True我会得到包含锚点/别名的那些对象的浅地图。

Ant*_*hon 4

您在文档中看不到的deep=True原因是您通常不需要将其用作 PyYAML 包的最终用户。

constructor.py如果您跟踪该用途中方法的使用,deep=您会发现construct_mapping()construct_sequence()在类中BaseConstructor(),并且这两个方法都会调用BaseConstructor.construct_object(). 该方法中要研究的相关代码是:

    if tag_suffix is None:
        data = constructor(self, node)
    else:
        data = constructor(self, tag_suffix, node)
    if isinstance(data, types.GeneratorType):
        generator = data
        data = next(generator)
        if self.deep_construct:
            for dummy in generator:
                pass
        else:
            self.state_generators.append(generator)
Run Code Online (Sandbox Code Playgroud)

特别是for其中的循环,只有在deep=True传入时才会执行。

粗略地说,如果数据来自生成器的构造函数,那么它会遍历该数据(在循环中for)直到生成器耗尽。通过这种机制,这些构造函数可以包含yield创建一个基础对象,其详细信息可以在yield. 因为它们只是yield此类构造函数中的一个,例如用于映射(构造为 Python dict):

def construct_yaml_map(self, node):
    data = {}
    yield data
    value = self.construct_mapping(node)
    data.update(value)
Run Code Online (Sandbox Code Playgroud)

我将此称为两步过程(一步到yield方法结束的下一步。

在这样的两步构造函数中,data要生成的内容被构造为空,生成,然后填充。之所以如此,是因为您已经注意到了:递归。如果存在对data下面某处的 self 引用,data则在构造其所有子级之后无法构造它,因为它必须等待自身构造完成。

deep参数间接控制是否递归地构建或附加到self.state_generators稍后要解析的列表中的潜在生成器的对象。

然后,构建 YAML 文档可以归结为构建顶级对象并循环遍历潜在的递归对象,直到self.state_generators没有生成器剩下(这一过程可能需要多次传递)。

  • 如果您转储的数据结构在多个位置附加了相同的对象/映射/序列,您将在 YAML 中获得锚点和别名,然后您需要“deep=True”才能加载它们。如果您转储的数据在某个时刻有一个对象,该对象“下方”本身有一个自引用,您也会获得锚点和别名,但您需要 `deep=True` **和** 两步过程由“yield”提供,以便能够加载该 YAML。因此,我总是使用“yield”和“deep=True”为非标量(潜在的(自)递归标量)创建构造函数,尽管某些 YAML 文档不需要。 (2认同)