使用Python deepmerge与ruamel.yaml合并YAML时丢失注释如何解决
问题根因
注释丢失、缩进异常问题核心原因如下:
- 你使用的
deepmerge库仅支持普通Python字典/列表的合并,无法识别ruamel.yaml加载生成的CommentedMap/CommentedSeq等带注释元数据的特殊结构,合并过程中会直接丢弃注释属性,同时破坏注释和节点的绑定关系导致缩进异常。 - ruamel.yaml的所有注释都存储在节点的
ca属性中,合并时需要主动同步该属性才能保留注释。
修复后实现代码
import ruamel.yaml def recursive_merge(merge_from, merge_into): """递归合并两个ruamel.yaml加载的带注释结构 merge_from: 优先级高的配置,会覆盖merge_into的同键值,新键直接添加 merge_into: 被合并的基础配置 """ if not isinstance(merge_from, dict) or not isinstance(merge_into, dict): # 非字典类型直接返回来源值 return merge_from # 遍历要合并的所有键 for key, value in merge_from.items(): if key in merge_into and isinstance(merge_into[key], dict) and isinstance(value, dict): # 两边都是字典,递归合并子节点 recursive_merge(value, merge_into[key]) else: # 直接赋值同步值和关联注释 merge_into[key] = value # 同步当前键对应的注释属性 if hasattr(merge_from, 'ca') and key in merge_from.ca.items: merge_into.ca.items[key] = merge_from.ca.items[key] # 同步父节点的全局注释 if hasattr(merge_from, 'ca'): merge_into.ca.comment = merge_from.ca.comment merge_into.ca.end = merge_from.ca.end return merge_into fileA = "source.yaml" fileB = "dest.yaml" yaml = ruamel.yaml.YAML() # 保留原始字符串引号配置 yaml.preserve_quotes = True # 保持缩进和原始文件一致 yaml.indent(mapping=4, sequence=4, offset=2) with open(fileA, 'r', encoding='utf-8') as f: fileAdictionary = yaml.load(f) with open(fileB, 'r', encoding='utf-8') as f: fileBdictionary = yaml.load(f) # 合并逻辑和原代码保持一致:将dest的配置合并到source上 result = recursive_merge(fileBdictionary, fileAdictionary) with open('output.yaml', 'w', encoding='utf-8') as f: yaml.dump(result, f)
效果说明
运行上述代码后,生成的output.yaml会完整保留dest.yaml中所有参数的注释,且注释缩进和原始文件保持一致,字符串参数的引号也可通过preserve_quotes配置保留。
补充说明
- 上述代码已适配你给出的字典嵌套类YAML结构,如果你需要合并带列表的YAML,可在递归函数中补充
CommentedSeq类型的合并逻辑。 - 如果你需要调整合并优先级(比如让source.yaml的配置覆盖dest.yaml),调换
recursive_merge的两个入参顺序即可。
内容的提问来源于stack exchange,提问作者user2713498
相关产品推荐
相关产品推荐

