结论:.env文件仅负责加载环境变量,不参与模块调度;真正的模块级配置切换需由代码根据环境变量动态判断并导入,如通过settings.py统一入口按env值选择加载settings_dev.py或settings_prod.py。

直接说结论:不能靠 .env 文件“动态管理模块配置”,它只负责加载环境变量;真正的“模块级配置切换”必须由代码层根据这些变量做判断和导入——.env 是输入,不是调度器。
为什么 load_dotenv 本身不支持“按环境自动切换模块”
load_dotenv() 的作用非常单纯:读取文件、解析键值对、注入到 os.environ。它不会主动触发任何模块导入、也不会识别 ENV=prod 就自动去 import config.prod。如果你期望“改个 .env 就自动切数据库连接模块”,那这个逻辑必须自己写。
- 常见错误现象:
load_dotenv(".env.prod")执行后,os.getenv("DB_HOST")能取到值,但from config import database仍加载的是开发版模块 - 根本原因:Python 导入机制在模块首次 import 时就已固化,环境变量变化不影响已导入的模块
- 正确思路:把环境变量当作“开关”,在配置模块(如
settings.py)里用if/elif或工厂函数决定返回哪套实例
用 os.getenv("ENV") 控制配置模块加载的实际写法
推荐结构是让一个统一入口(比如 settings.py)根据环境变量动态选择子模块,而不是让每个业务模块自己读 ENV。
- 项目结构示例:
project/ ├── settings.py # 唯一配置入口 ├── settings_dev.py ├── settings_prod.py └── .env # 内容:ENV=prod
-
settings.py内容精简版:import os from importlib import import_module <p>env = os.getenv("ENV", "dev") module<em>name = f"settings</em>{env}" settings = import_module(module_name)</p><h1>把子模块的变量全部暴露出来</h1><p>DATABASE_URL = settings.DATABASE_URL DEBUG = settings.DEBUG</p> - 关键点:不要在
settings_dev.py里调用load_dotenv(),所有.env*文件应由启动脚本或顶层main.py统一加载
多个 .env 文件共存时的加载顺序与覆盖规则
python-dotenv 默认只加载一个文件,但你可以手动控制叠加顺序。常见需求是“基础配置 + 环境特有配置”,这时要明确谁覆盖谁。
- 典型做法:先加载
.env.base(通用项),再加载.env.prod(覆盖项)from dotenv import load_dotenv from pathlib import Path <p>base = Path("configs/.env.base") prod = Path("configs/.env.prod")</p><p>load_dotenv(base) # 先加载基础 load_dotenv(prod) # 后加载的同名变量会覆盖前面的</p> - 容易踩的坑:
-
load_dotenv()默认会跳过已存在的环境变量,所以如果ENV已被 shell 设置,.env里的ENV=dev不生效 - 路径写错导致静默失败(比如
dotenv_path="config/.env"但实际目录是configs/),建议加verbose=True调试 - Git 提交了
.env.prod—— 敏感信息泄露风险极高,必须进.gitignore
-
生产环境部署时 .env 文件路径和权限的硬性约束
本地开发时 .env 放根目录很自然,但上线后往往没权限写文件、路径也不固定,这时候硬编码路径会崩。
- 安全且可移植的做法:
- 用绝对路径 + 环境变量定位:比如
load_dotenv(os.getenv("CONFIG_DIR", "/etc/myapp") + "/.env.prod") - 禁止在代码里写死
/home/deploy/app/.env这类路径,运维应通过容器-v或 K8sConfigMap注入 - Linux 下确保
.env文件权限为600(chmod 600 .env.prod),否则load_dotenv会拒绝读取(默认启用安全检查)
- 用绝对路径 + 环境变量定位:比如
最常被忽略的一点:python-dotenv 在生产环境默认开启 encoding="utf-8",但如果 .env 是 Windows 编辑器保存的 UTF-8 with BOM,会导致解析失败且无提示——务必用 file -i .env.prod 检查编码,或强制指定 encoding="utf-8-sig"。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











