在 Python 中使用顶级列表注释的深度复制 YAML



我正在尝试使用 ruamel.yaml 将以下 yaml 文件转储到多个(不同的)文件中:

C:
f:
# comment
- - l1
- l2: '5'

如果我尝试模仿deepcopy,注释会导致深拷贝版本出错:

import copy
from ruamel.yaml import YAML
yaml = YAML()
conf = None
with open("input.yaml", 'r') as inf:
conf = yaml.load(inf)
conf2 = copy.deepcopy(conf)
with open("out1.yaml", 'w') as outf:
yaml.dump(conf, outf)
try:
with open("out2.yaml", 'w') as outf:
yaml.dump(conf2, outf)
print("all good")
except AssertionError:
raise SystemExit("Deep copy failed")

有没有替代方法可以将带有此类注释的加载 YAML 转储到多个文件中?

出现此问题主要是因为ruamel.yaml开发 不要从您的注释# comment所属的数据结构开始(现在也没有)。它更容易的事实 向已创建的节点添加注释(即 在解析器遇到注释之前 YAML 文档)而不是添加它 到以下节点(在文档末尾可能不会显示 向上)。

在您的示例中,注释可能与键f相关联,以 单元素序列的第一个元素,或第一个元素 的双项序列。ruamel.yaml确实尝试进行一些重新排列,这已经 导致过去在与 两个连续的节点,这就是merge_comments试图通过查找来解决的问题 这些评论是否相等。

这是一个权宜之计,但效果很好 如果您将ruamel.yaml用于加载-修改-保存的预期目的,但 DeepCopy 不保留此引用,导致不平等,因此AssertionError

对此的快速而肮脏的解决方案是使merge_comments成为无操作:

import copy
from ruamel.yaml import YAML
yaml = YAML()
conf = None
with open("input.yaml", 'r') as inf:
conf = yaml.load(inf)
conf2 = copy.deepcopy(conf)
with open("out1.yaml", 'w') as outf:
yaml.dump(conf, outf)
yaml.representer.merge_comments = lambda x, y: None
try:
with open("out2.yaml", 'w') as outf:
yaml.dump(conf2, outf)
print("all good")
except AssertionError:
raise SystemExit("Deep copy failed")

这给了:

all good

内容out1.yaml

C:
f:
# comment
- - l1
- l2: '5'

out2.yaml

C:
f:
# comment
- - l1
- l2: '5'

这个问题被"增强"为__deepcopy__列表和映射的表示形式,执行 保存注释、流、格式、定位点等信息的属性 不遵循文档中的建议:

如果deepcopy() 实现需要制作 组件,它应该与组件一起调用 deepcopy() 函数 作为第一个参数,将备忘录字典作为第二个参数。

但改变这一点并不能解决问题,这是一个更结构性的解决方案。 将是对评论将适用于什么有一个明确的定义,并且 取消merge_comments.那应该 包括多行注释的拆分,如下所示:

# this documents has some non-trivial
# comment lines
# first item follows
- 42
# end of first item
# second item follows
- 196
# end of second item
# final comment of the document

目前,以上内容将加载三个(多行)评论,但 IMO 将其解释为六条评论更为恰当。这 主要任务是定义拆分此类注释而不解释注释的含义,仅使用空行。

此外,节点分配可能会考虑注释的缩进级别。

最新更新