You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重置含换行注释的列表为空时篡改其他值,重载YAML报错

ruamel.yaml 修改YAML后格式错乱、二次加载报错的解决方法

问题重现

原始YAML文件(test.yml)

key1:
  # comment1
  - t1: t_value
    u1: u_value
  - t2: t_value
    u2: u_value
key2:
  # comment2
  key21:
    k1: 0.1
    k2: 0.2
    k3: 0.6

执行的Python代码

import ruamel.yaml as ruamel

_ruamel = ruamel.YAML()
_ruamel.preserve_quotes = True
_ruamel.indent(mapping=2, sequence=4, offset=2)
_ruamel.width = 120

with open('test.yml') as f:
    data = f.read()
    data = _ruamel.load(data.encode())

data['key1'] = []
with open('test.yml', 'w') as f:
    _ruamel.dump(data, f)

异常表现

修改后的YAML出现格式错乱,key2的子项被错误合并,且空序列的缩进异常:

key1:
  # comment1
    []
key2:
  # comment2
  key21: k1: 0.1
    k2: 0.2
    k3: 0.6

再次执行相同代码时,触发扫描错误:

ruamel.yaml.scanner.ScannerError: mapping values are not allowed here
  in "<byte string>", line 6, column 12:
      key21: k1: 0.1
               ^ (line: 6)

问题原因

  1. 直接赋值data['key1'] = []替换了原有的序列节点,导致原节点关联的注释失去正确附着位置,空序列的缩进也出现错误。
  2. 手动读取文件内容再编码后加载的方式,干扰了ruamel.yaml对节点结构的正确解析,间接导致嵌套映射的格式输出异常。

解决方案

修改后的代码

import ruamel.yaml as ruamel

_ruamel = ruamel.YAML()
_ruamel.preserve_quotes = True
_ruamel.indent(mapping=2, sequence=4, offset=2)
_ruamel.width = 120

with open('test.yml') as f:
    # 直接从文件对象加载,无需手动处理编码
    data = _ruamel.load(f)

# 清空原序列的内容,而非替换整个节点,保留注释关联
del data['key1'][:]

with open('test.yml', 'w') as f:
    _ruamel.dump(data, f)

正确输出结果

修改后的YAML会保留原有注释和未修改节点的格式:

key1:
  # comment1
key2:
  # comment2
  key21:
    k1: 0.1
    k2: 0.2
    k3: 0.6

原理说明

ruamel.yaml的核心特性是保留YAML的结构、注释和格式信息,每个序列/映射节点都有对应的内部对象。直接替换节点会丢失原有的注释绑定关系,而清空原序列内容del data['key1'][:]会保留节点本身,注释会自动附着在正确的位置。同时,直接从文件对象加载是ruamel推荐的方式,能避免编码处理带来的潜在问题,确保节点结构解析准确。

内容的提问来源于stack exchange,提问作者Aishwarya Anegundi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 02:56:22