【问题标题】:What does deep=True do in pyyaml.Loader.construct_mapping?deep=True 在 pyyaml.Loader.construct_mapping 中有什么作用?
【发布时间】:2017-05-05 18:56:26
【问题描述】:

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

def some_constructor(loader, node):
    value = loader.construct_mapping(node, deep=True)
    return SomeClass(value)

deep=True 有什么作用?我在pyyaml documentation 中没有看到它。

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

【问题讨论】:

    标签: python-2.7 pyyaml


    【解决方案1】:

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

    如果您跟踪 constructor.py 中使用 deep= 的方法的使用,您会来到 BaseConstructor() 类中的 construct_mapping()construct_sequence(),并且这两个都调用 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)
    

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

    Rougly 说如果来自构造函数的数据是生成器,那么它会遍历该数据(在for 循环中)直到生成器耗尽。使用该机制,那些构造函数可以包含yield 来创建基础对象,其详细信息可以在yield 之后填写。因为它们在这样的构造函数中只有一个yield,例如用于映射(构造为 Python dicts):

    def construct_yaml_map(self, node):
        data = {}
        yield data
        value = self.construct_mapping(node)
        data.update(value)
    

    我称之为两步过程(一步到yield,然后是方法的末尾。

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

    deep 参数间接控制作为潜在生成器的对象是递归构建还是附加到列表self.state_generators 以供稍后解析。

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

    【讨论】:

    • 所以如果我有递归数据结构,我就不能使用它(有道理);不过,我为什么要使用它呢?换句话说,我是否可以在我的数据中查找可以解释何时需要使用 deep=True 的内容?
    • 如果您转储在多个位置附加了相同对象/映射/序列的数据结构,您将在 YAML 中获得锚点和别名,然后您需要 deep=True 才能加载这些.如果您转储的数据在某个点有一个“下面”本身有自引用的对象,您也会得到锚点和别名,但您需要deep=True 两步yield 提供的进程能够加载该 YAML。所以我总是使用yielddeep=True 为非标量(潜在的(自)递归的)创建构造函数,尽管某些 YAML 文档不需要。
    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-20
    • 2018-03-01
    • 2018-04-11
    相关资源
    最近更新 更多