正如@Hadyniak 已经指出您错误地使用了merge
keys。由于别名 *B 在
composer 步骤,在解释之前的<<merge 键
构造器步骤,后者实际上接收一个字典列表,它们是
结合较早出现的dicts的键值优先。如果
处理顺序碰巧不同,你会得到一个错误,并且
IMO 合并密钥文档没有明确指定别名应该
先展开。
Hadyniak 的解决方案会让你结束
c['A'] 和 c['C'] 是同一个字典,这可能不是你想要的:
import ruamel.yaml
yaml_str = """\
A:
&B
- x: 1
y: 2
- x: 10
y: 20
C:
*B
"""
yaml = ruamel.yaml.YAML()
c = yaml.load(yaml_str)
print(c['A'] is c['C'], c['A'] == c['C'])
c['A'][0]['x'] = 42
print('x:', c['C'][0]['x'])
给出:
True True
x: 42
如果这不是您想要的,您仍然可以使用合并键,但在作为序列元素的字典上:
import ruamel.yaml
yaml_str = """\
A:
- &B1
x: 1
y: 2
- &B2
x: 10
y: 20
C:
- <<: *B1
- <<: *B2
"""
yaml = ruamel.yaml.YAML()
c = yaml.load(yaml_str)
print(c['A'] is c['C'], c['A'] == c['C'])
c['A'][0]['x'] = 42
print('x:', c['C'][0]['x'])
给出:
False True
x: 1
或者,您可以告诉 ruamel.yaml 的作曲家部分扩展别名而不是使用引用:
import copy
yaml_str = """\
A:
&B
- x: 1
y: 2
- x: 10
y: 20
C:
*B
"""
yaml = ruamel.yaml.YAML()
yaml.composer.return_alias = lambda s: copy.deepcopy(s)
c = yaml.load(yaml_str)
print(c['A'] is c['C'], c['A'] == c['C'])
c['A'][0]['x'] = 42
print('x:', c['C'][0]['x'])
给出:
False True
x: 1
以上仅适用于ruamel.yaml>0.17.2,对于旧版本,您需要复制和修改compose_node方法:
import copy
yaml_str = """\
A:
&B
- x: 1
y: 2
- x: 10
y: 20
C:
*B
"""
class MyComposer(ruamel.yaml.composer.Composer):
def compose_node(self, parent, index):
# type: (Any, Any) -> Any
if self.parser.check_event(ruamel.yaml.events.AliasEvent):
event = self.parser.get_event()
alias = event.anchor
if alias not in self.anchors:
raise ComposerError(
None,
None,
'found undefined alias {alias!r}'.format(alias=alias),
event.start_mark,
)
return copy.deepcopy(self.anchors[alias])
event = self.parser.peek_event()
anchor = event.anchor
if anchor is not None: # have an anchor
if anchor in self.anchors:
ws = (
'\nfound duplicate anchor {!r}\nfirst occurrence {}\nsecond occurrence '
'{}'.format((anchor), self.anchors[anchor].start_mark, event.start_mark)
)
warnings.warn(ws, ruamel.yaml.error.ReusedAnchorWarning)
self.resolver.descend_resolver(parent, index)
if self.parser.check_event(ruamel.yaml.events.ScalarEvent):
node = self.compose_scalar_node(anchor)
elif self.parser.check_event(ruamel.yaml.events.SequenceStartEvent):
node = self.compose_sequence_node(anchor)
elif self.parser.check_event(ruamel.yaml.events.MappingStartEvent):
node = self.compose_mapping_node(anchor)
self.resolver.ascend_resolver()
return node
yaml = ruamel.yaml.YAML()
yaml.Composer = MyComposer
c = yaml.load(yaml_str)
print(c['A'] is c['C'], c['A'] == c['C'])
c['A'][0]['x'] = 42
print('x:', c['C'][0]['x'])
这也给出了:
False True
x: 1