加载包含不同嵌套级别的锚点的文件时,锚点似乎丢失了,并且键保持为空。
加载以下文件时:
---
Dict1:
- InnerDict: &inner
key: val
Dict2:
InnerDict:
<<: *inner
Dict3:
- InnerDict:
<<: *inner
...
...使用代码(Python 3.7,ruamel.yaml版本0.15.78):
from ruamel.yaml import YAML
with open("file.yaml") as infile:
content = YAML(typ='rt', pure=True).load(infile)
print(content)
...给出:
{'Dict1': [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])],
'Dict2': ordereddict([('InnerDict', ordereddict())]),
'Dict3': [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]}
...
Dict2
的内部字典保留为空。在安全模式下,两种情况下的锚都将按预期进行解释。
它是故意的还是一个错误?
最佳答案
那绝对是一个错误,它与广度优先有关
在数据结构中构建映射。到时候
构造InnerDict
下的Dict2
,嵌套在Dict1
下的一个
不完全可用。 InnerDict
下的Dict3
位于
相同的深度,因此可以正确构造(
如果您删除Dict1
构造中的破折号,则首先合并
使锚点出现在较浅的位置)。
解决此问题的一种方法,除了安装ruamel.yaml>=0.15.79
之外,还可以通过
提供替代的构造函数,该结构强制进行深度优先处理:
import sys
import ruamel.yaml
class MyConstructor(ruamel.yaml.constructor.RoundTripConstructor):
def construct_yaml_map(self, node):
data = ruamel.yaml.comments.CommentedMap()
data._yaml_set_line_col(node.start_mark.line, node.start_mark.column)
yield data
self.construct_mapping(node, data, deep=True)
self.set_collection_style(data, node)
MyConstructor.add_constructor(
u'tag:yaml.org,2002:map', MyConstructor.construct_yaml_map
)
yaml = ruamel.yaml.YAML()
yaml.Constructor = MyConstructor
yaml_str = """\
Dict1:
- InnerDict: &inner
key: val
Dict2:
InnerDict:
<<: *inner
Dict3:
- InnerDict:
<<: *inner
"""
data = yaml.load(yaml_str)
for k in data:
print(k, data[k])
print('---------')
yaml.dump(data, sys.stdout)
产生:
Dict1 [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]
Dict2 ordereddict([('InnerDict', ordereddict([('key', 'val')]))])
Dict3 [ordereddict([('InnerDict', ordereddict([('key', 'val')]))])]
---------
Dict1:
- InnerDict: &inner
key: val
Dict2:
InnerDict:
<<: *inner
Dict3:
- InnerDict:
<<: *inner
(由于
data
的转储是正确的,即使没有上述“补丁”,此测试往返时以前未检测到)