如何解决序列的 YAML 锚点?
A:
&B
- x: 1
y: 2
- x: 10
y: 20
C:
<<: *B
通过以下方式读入python:
from ruamel.yaml import YAML
filename = 'data/configs/debug_config.yml'
with open(filename) as f:
c = YAML(typ='safe').load(f)
print(c)
产量:
{'A': [{'x': 1,'y': 2},{'x': 10,'y': 20}],'C': {'x': 1,'y': 2}}
可以看出锚点B
只包含序列的第一个元素。为什么?我想要一个包含整个序列的锚点,这样 python 字典中 A
和 C
的值是相同的。这怎么办?
解决方法
锚点 B
包含来自 A
的所有元素,但您正在使用合并键 <<
(source) 合并它们:
如果与合并键关联的值是一个序列,那么这个序列应该包含映射节点,并且这些节点中的每一个都按照其在序列中的顺序依次合并。 序列中较早映射节点中的键会覆盖较晚映射节点中指定的键。
因此,A
中的第一项会覆盖第二项。
Remove <<:
和 C
将与 A
是同一个字典:
A: &B
- x: 1
y: 2
- x: 10
y: 20
C: *B
产量:
{
"A": [
{
"y": 2,"x": 1
},{
"y": 20,"x": 10
}
],"C": [
{
"y": 2,"x": 10
}
]
}
您可以使用此示例检查合并顺序:
A: &B
- x: 1
y: 2
- x: 10
new: 333
C:
<<: *B
产量:
{
"A": [
{
"y": 2,{
"x": 10,"new": 333
}
],"C": {
"y": 2,"x": 1,"new": 333
}
}
,
正如@Hadyniak 已经指出您错误地使用了 merge
keys。由于别名 *B
在
composer 步骤,在解释 <<
中的合并键之前
构造函数步骤,后者实际上接收一个字典列表,它们是
结合优先出现的较早字典的键值。如果
处理顺序碰巧不同,你会得到一个错误,并且
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['C'][0]['x'])
给出:
False True
x: 1
或者,您可以告诉 ruamel.yaml
的 composer 部分扩展别名而不是使用引用:
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['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['C'][0]['x'])
这也给出:
False True
x: 1
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。