2017-02-24 28 views
1

我想通过别名中的构造函数使用锚定数据,但别名想要使用预构造函数数据。使用pyyaml或ruamel.yaml构造函数作为另一个别名

我从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树中获取数据,而不是从构造函数得到的数据。

有什么办法可以使这项工作?

回答

0

为了使用YAML的合并功能的固定式“”必须是一个映射(Python的dict)和映射被插入在该点的其他映射的键/值对,你这样做:

<<: *other 

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

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

+0

我明白映射功能是如何工作的,'!l2d'标签和'l2d_constructor'函数将'a'序列更改为字典,就像您在python对象中看到的那样。 我的希望是,构造函数从序列到映射的变化意味着我可以像yaml中的映射那样处理'a'值,但我越来越认为在那个阶段解析过程已经太晚了,在'!l2d'和相应的构造函数之前处理<'。 – tommyvn

+0

是的,解析是由解析器完成的,它并不是由标签创建的。你可以做的一件事就是将'''改成其他独特的东西(例如'>>'),并且标记映射以加载类似于对象的字典,它解释'>>'的值。或者你可以替换'constructor.py'中的合并工具来做正确的事情。 – Anthon

相关问题