使用PyYAML引入YAML后添加新字典键的问题
PyYAML引入文件后合并字典的解决办法
问题场景
你有两个YAML文件:
login.yaml内容:
id: 1 login: user: name pass: secret
尝试在config.yaml里引入login.yaml并给目标字典新增example键,写法如下但无法正常工作:
login_info: !include login.yaml example: random
单独使用!include或者单独写example: random都没问题,但组合后无法实现字典合并。使用的是PyYAML处理YAML文件引入。
问题根源
PyYAML默认的!include构造器是直接用引入的内容替换当前节点,不支持和同层级的其他键值对合并。当你在login_info下同时写!include和example时,解析器要么把!include当作一个普通键,要么直接忽略后续的键,导致合并失败。
两种可行解决方案
方案1:自定义支持合并的引入构造器
自己写一个!include_merge标签的构造器,在加载时自动把引入的字典和当前节点的其他键合并:
import yaml from pathlib import Path def include_merge(loader, node): # 获取要引入的文件路径 file_path = Path(loader.construct_scalar(node)) # 加载目标YAML文件 with open(file_path, 'r', encoding='utf-8') as f: included_dict = yaml.load(f, Loader=yaml.FullLoader) # 解析当前节点的同层级键值对 parent_mapping = loader.construct_mapping(loader.nodes[loader.idx - 1]) # 合并:用新增键覆盖或补充引入的字典 included_dict.update(parent_mapping) return included_dict # 注册自定义构造器到FullLoader yaml.FullLoader.add_constructor('!include_merge', include_merge) # 加载配置文件 with open('config.yaml', 'r', encoding='utf-8') as f: config = yaml.load(f, Loader=yaml.FullLoader) print(config)
对应的config.yaml写法改成:
login_info: !include_merge login.yaml example: random
方案2:加载后手动合并字典
不想改构造器的话,可以分别加载两个文件,再手动合并数据:
import yaml # 加载login.yaml的内容 with open('login.yaml', 'r', encoding='utf-8') as f: login_data = yaml.load(f, Loader=yaml.FullLoader) # 加载config.yaml,只保留新增的键 with open('config.yaml', 'r', encoding='utf-8') as f: config_data = yaml.load(f, Loader=yaml.FullLoader) # 合并字典,把新增键加入login_data login_data.update(config_data['login_info']) config_data['login_info'] = login_data print(config_data)
此时config.yaml要调整成只写新增键:
login_info: example: random
注意点
- 自定义构造器时要注意文件路径的正确性,建议用绝对路径或者基于当前脚本工作目录的相对路径。
- 如果引入的YAML内容不是字典,要调整合并逻辑,避免抛出类型错误。
内容的提问来源于stack exchange,提问作者khl
相关产品推荐
相关产品推荐

