重置含换行注释的列表为空时篡改其他值,重载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)
问题原因
- 直接赋值
data['key1'] = []替换了原有的序列节点,导致原节点关联的注释失去正确附着位置,空序列的缩进也出现错误。 - 手动读取文件内容再编码后加载的方式,干扰了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
相关产品推荐
相关产品推荐

