在Python项目开发中,我们通常会根据配置的使用场景选择不同的存储方式,环境变量适合存储敏感信息和环境差异化配置,配置文件适合存储项目通用固定配置,配置中心适合存储需要动态更新的全局配置。合理设置三者的优先级可以保证配置加载符合预期。

三级配置的适用场景
在设置优先级之前,我们需要先明确三种配置方式的适用场景,这样才能让优先级设计更合理:
- 配置中心:适合存储需要动态修改、多服务共享的配置,比如功能开关、全局限流阈值等,优先级最低,作为配置的默认值来源。
- 配置文件:适合存储项目通用的固定配置,比如数据库连接的基础参数、日志格式等,优先级高于配置中心,用于覆盖默认配置。
- 环境变量:适合存储不同部署环境的差异化配置、敏感信息比如数据库密码、API密钥等,优先级最高,用于覆盖前两者的配置。
三级优先级实现思路
整体的加载逻辑为:先加载配置中心的配置作为基础值,再读取配置文件中的配置覆盖已有值,最后读取环境变量中的配置再次覆盖,最终得到应用使用的配置。下面我们分步骤实现这个逻辑。
1. 配置中心模拟实现
这里我们用一个简单的字典模拟配置中心,实际项目中可以替换为Nacos、Apollo等真实配置中心的SDK调用:
# 模拟配置中心的配置,实际项目中替换为配置中心的查询逻辑
def get_config_from_center():
# 模拟从配置中心拉取到的配置
center_config = {
"db_host": "127.0.0.1",
"db_port": 3306,
"log_level": "INFO",
"feature_switch": False
}
return center_config
2. 配置文件读取实现
这里我们使用YAML格式的配置文件作为示例,需要先安装pyyaml库,配置文件内容如下:
# config.yaml 配置文件内容 db_host: "192.168.0.1" db_port: 3307 log_level: "DEBUG"
对应的读取代码如下:
import yaml
def get_config_from_file(file_path="config.yaml"):
try:
with open(file_path, "r", encoding="utf-8") as f:
file_config = yaml.safe_load(f)
return file_config if file_config else {}
except FileNotFoundError:
# 配置文件不存在时返回空字典
return {}
3. 环境变量读取实现
环境变量通常通过os模块读取,我们约定环境变量的命名规则为全大写,多个单词用下划线连接,和配置项的key对应:
import os
def get_config_from_env(prefix="APP_"):
env_config = {}
# 遍历所有环境变量,筛选带指定前缀的变量
for key, value in os.environ.items():
if key.startswith(prefix):
# 去掉前缀,转为小写作为配置key
config_key = key[len(prefix):].lower()
env_config[config_key] = value
return env_config
4. 三级配置合并实现
按照优先级从低到高合并配置,后加载的配置会覆盖先加载的同名配置:
def merge_config():
# 1. 加载配置中心配置(优先级最低)
final_config = get_config_from_center()
# 2. 加载配置文件配置,覆盖配置中心配置
file_config = get_config_from_file()
for key, value in file_config.items():
final_config[key] = value
# 3. 加载环境变量配置,覆盖前两者的配置(优先级最高)
env_config = get_config_from_env()
for key, value in env_config.items():
final_config[key] = value
return final_config
完整使用示例
我们设置环境变量APP_DB_PORT=3308,然后执行配置合并,查看最终配置结果:
import os
# 设置测试环境变量
os.environ["APP_DB_PORT"] = "3308"
os.environ["APP_FEATURE_SWITCH"] = "True"
if __name__ == "__main__":
config = merge_config()
print("最终配置结果:")
for key, value in config.items():
print(f"{key}: {value}")
执行上述代码后,输出结果如下:
最终配置结果: db_host: 192.168.0.1 db_port: 3308 log_level: DEBUG feature_switch: True
可以看到,db_host来自配置文件,覆盖了配置中心的127.0.0.1;db_port来自环境变量,覆盖了配置文件的3307;log_level来自配置文件,覆盖了配置中心的INFO;feature_switch来自环境变量,覆盖了配置中心的False,符合我们设计的三级优先级逻辑。
注意事项
- 环境变量的取值都是字符串类型,如果需要其他类型比如整数、布尔值,需要在读取后进行类型转换,避免类型错误。
- 配置中心的配置建议设置缓存机制,避免每次请求都拉取配置中心,降低性能开销。
- 敏感配置比如密码、密钥只通过环境变量或者配置中心存储,不要写在配置文件中,避免泄露风险。
- 如果配置项不存在于三个配置源中,需要设置合理的默认值,避免应用运行时出现KeyError错误。