您可以使用人工编写的YAML执行以下操作:
foo: &foo_anchor
key1: v1
key2: v2
key3: v3
bar:
<<: *foo_anchor
key2: override_value
我想像使用PyYAML一样以编程方式生成输出。似乎很棘手!据我所知,默认情况下,PyYAML仅在遇到相等的对象时才生成锚/引用(并且顺序可能未定义,而在此示例中,bar
必须引用foo
,而不是另一种方式)。我已经尝试了一些方法-定义了YamlReference
类并在覆盖的Dumper.serialize_node
方法中检查了其标记-但尝试执行以下操作:
if node.tag.endswith('magic.prefix.YamlReference'):
alias = node.value[0].value
self.emit(yaml.events.AliasEvent(alias))
super(Dumper, self).anchor_node(node.value[1])
super(Dumper, self).serialize_node(node.value[1], parent, idx)
符合预期的事件流。这可能吗?
答案 0 :(得分:1)
好吧,你可以做这样的事情:
import yaml
class Merger(object):
pass
def merger_representer(dumper, data):
return dumper.represent_scalar(u'tag:yaml.org,2002:merge', '<<')
yaml.add_representer(Merger, merger_representer)
foo = {'key1': 'v1', 'key2': 'v2', 'key3': 'v3'}
root = {
'foo': foo,
'bar': {
Merger(): foo,
'key2': 'override_value'
}
}
print(yaml.dump(root, sort_keys=False))
输出为:
foo: &id001
key1: v1
key2: v2
key3: v3
bar:
<<: *id001
key2: override_value
sort_keys=False
确保键的正确顺序,它要求Python> = 3.7和PyYAML> = 5.1(感谢@tinita)。您无法控制所生成的锚名称,但是此YAML等效于您的名称。
您需要Merger
类来强制PyYAML发出<<
(使用普通的字符串键,它将发出'<<'
,以免与合并键混淆)
答案 1 :(得分:-1)
实现此目标的一种方法是制作一个包含适当内容的类
有关合并信息的信息,并且仍然允许查找
data['bar']['key1']
。当然,您需要使用适当的表示符正确转储此类。
这是ruamel.yaml(免责声明,我是 该程序包的作者)确实允许来回合并地图:
import sys
import ruamel.yaml
yaml_str = """\
foo: &foo_anchor
key1: v1
key2: v2
key3: v3
bar:
<<: *foo_anchor
key2: override_value
"""
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
给出:
foo: &foo_anchor
key1: v1
key2: v2
key3: v3
bar:
<<: *foo_anchor
key2: override_value
因此,我建议您查看类CommentedMap
以及这是怎么回事
在constructor.py
和representer.py
中处理。
如果您可以升级到ruamel.yaml
,则可以执行以下操作:
cm = ruamel.yaml.comments.CommentedMap
data = cm()
data['foo'] = foo = cm(key1='v1', key2='v2', key3='v3')
foo.yaml_set_anchor('foo_anchor')
data['bar'] = bar = cm(key2='override_value')
bar.add_yaml_merge([(0, foo)])
yaml = ruamel.yaml.YAML()
yaml.dump(data, sys.stdout)
从头开始,它提供了与您期望的类似的东西:
foo: &foo_anchor
key1: v1
key2: v2
key3: v3
bar:
<<: *foo_anchor
key2: override_value
当然,以下各项可以按预期工作:
print(list(data['bar'].keys()))
print(data['bar']['key3'])
给出:
['key2', 'key1', 'key3']
v3