如何在PyYAML中保留!ENV原标记并保存修改后的配置文件
解决YAML加载替换环境变量但保存保留!ENV标记的问题
核心思路是用自定义类型封装环境变量标记:加载时将!ENV VAR_NAME解析为继承自字符串的自定义对象(既保留原始变量名,又能直接当作环境变量值使用);保存时通过YAML代表器将该自定义对象还原为!ENV VAR_NAME格式。
实现步骤
- 定义自定义EnvVar类
继承自str,既让程序能直接当作字符串使用,又存储原始环境变量名用于保存时还原:
import os import yaml class EnvVar(str): def __new__(cls, var_name): # 从环境变量取值,创建str子类实例 env_value = os.getenv(var_name, "") obj = super().__new__(cls, env_value) # 存储原始变量名 obj.var_name = var_name return obj
- 注册YAML构造器(加载时解析!ENV标记)
将YAML中的!ENV VAR_NAME节点解析为EnvVar实例:
def env_var_constructor(loader, node): # 提取!ENV后面的变量名字符串 var_name = loader.construct_scalar(node) return EnvVar(var_name) # 注册到SafeLoader yaml.SafeLoader.add_constructor('!ENV', env_var_constructor)
- 注册YAML代表器(保存时还原!ENV标记)
将EnvVar实例序列化为!ENV VAR_NAME格式:
def env_var_representer(dumper, data): # 用原始变量名生成!ENV标记的YAML节点 return dumper.represent_scalar('!ENV', data.var_name) # 注册到SafeDumper(用add_multi_representer处理子类) yaml.SafeDumper.add_multi_representer(EnvVar, env_var_representer)
- 加载、修改、保存配置
# 加载配置 with open('config.yaml', 'r') as f: cfg = yaml.load(f, Loader=yaml.SafeLoader) # 程序中直接使用环境变量值(和普通字符串无差异) print(f"数据库密码:{cfg['db_password']}") # 修改其他配置项 cfg['db_table'] = 'user_data' cfg['app_hash'] = 'a1b2c3d4' # 保存配置(自动保留!ENV标记) with open('modified_config.yaml', 'w') as f: yaml.dump(cfg, f, Dumper=yaml.SafeDumper, default_flow_style=False)
效果验证
- 加载时:
cfg['db_password']是环境变量的实际值,可直接使用 - 保存后:
db_password字段仍为!ENV DB_PASSWORD,其他修改项正常保留
内容的提问来源于stack exchange,提问作者harleypig
相关产品推荐
相关产品推荐

