【问题标题】:using a pyyaml or ruamel.yaml constructor as an achor for an alias使用 pyyaml 或 ruamel.yaml 构造函数作为别名的锚
【发布时间】:2017-07-15 14:47:12
【问题描述】:

我正在尝试使用通过别名中的构造函数传递的锚定数据,但是别名想要使用预构造函数数据。

我从 anthon 的 Is there a way to construct an object using PyYAML construct_mapping after all nodes complete loading? 中获得灵感,但仍然没有找到快乐。

下面是一些示例代码:

class L2D(dict):
    def __repr__(self):
        return('L2D({})'.format(dict.__repr__(self)))

def l2d_constructor(loader, node):
    print("constructing")
    instance = L2D.__new__(L2D)
    yield instance
    state = loader.construct_sequence(node, deep=True)
    instance.__init__(state)

yaml.add_constructor(u'!l2d', l2d_constructor)

print(yaml.load('''
a: !l2d
  - [e, f]
  - [g, h]
'''))

print("============")

print(yaml.load('''
a: &other !l2d
  - [e, f]
  - [g, h]
b:
  <<: *other
  a: b
  c: d
'''))

第一次加载有效,但我希望第二次加载输出是

constructing
{'a': L2D({'g': 'h', 'e': 'f'}), 'b': {'a': 'b', 'g': 'h', 'e': 'f', 'c': 'd'}}

我得到了

constructing
Traceback (most recent call last):
  File "test2.py", line 41, in <module>
    '''))
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/main.py", line 86, in load
    return loader.get_single_data()
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 56, in get_single_data
    return self.construct_document(node)
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 65, in construct_document
    for dummy in generator:
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 494, in construct_yaml_map
    value = self.construct_mapping(node)
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 265, in construct_mapping
    self.flatten_mapping(node)
  File "/tmp/tmp.1oRXCix7X3/venv/lib/python3.5/site-packages/ruamel/yaml/constructor.py", line 240, in flatten_mapping
    % subnode.id, subnode.start_mark)
ruamel.yaml.constructor.ConstructorError: while constructing a mapping
  in "<unicode string>", line 8, column 3:
      <<: *other
      ^ (line: 8)
expected a mapping for merging, but found sequence
  in "<unicode string>", line 5, column 5:
      - [e, f]
        ^ (line: 5)

constructing 打印表明构造函数已经完成了它的工作,但我怀疑它的别名是它试图从未更改的 yaml 树中获取数据,而不是从构造函数中获取结果数据。

我有什么办法可以完成这项工作吗?

【问题讨论】:

    标签: python yaml pyyaml ruamel.yaml


    【解决方案1】:

    为了使用 YAML 的合并功能,您的锚定“类型”需要是一个映射 (Python dict),并且该映射的键/值对插入到另一个映射中您执行操作的位置:

    <<: *other
    

    您的锚定类型是一个序列,在使用合并功能时这是不允许的。

    您应该查看merge documentation,您可以在其中看到锚定类型始终是映射。

    【讨论】:

    • 我了解映射功能的工作原理,!l2d 标记和l2d_constructor 函数将a 序列更改为字典,正如您在生成的python 对象中看到的那样。我希望构造函数从序列到映射的突变意味着我可以将 a 值视为 yaml 中的映射,但我越来越认为到那个阶段解析为时已晚,&lt;&lt; 是在!l2d和对应的构造函数之前处理。
    • 是的,&lt;&lt; 解释是由解析器完成的,它采用的是序列而不是标签的序列。您可以做的一件事是将&lt;&lt; 更改为其他独特的东西(例如&gt;&gt;)并标记映射以加载类似字典的对象,该对象解释&gt;&gt; 的值。或者您可以替换 constructor.py 中的合并工具来做正确的事情。
    猜你喜欢
    • 2020-05-20
    • 2011-11-05
    • 1970-01-01
    • 2017-07-02
    • 2017-12-08
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2015-04-17
    相关资源
    最近更新 更多