用python-dotenv加载.env文件是最轻量、最不易出错的方案,但需手动调用load_dotenv()且默认不覆盖已存在环境变量;os.getenv()无法读取.env文件因其只访问系统环境变量。

直接说结论:用 python-dotenv 加载 .env 文件是最轻量、最不易出错的方案,但必须手动调用 load_dotenv(),且它不会自动覆盖已存在的环境变量(除非显式传参)。
为什么不能只靠 os.getenv() 读取 .env 文件
os.getenv() 只读系统环境变量,完全不感知 .env 文件——它压根不会去磁盘找这个文件。你写 os.getenv("API_KEY") 返回 None,不是代码写错了,是根本没加载过 .env。
- 常见错误现象:
print(os.getenv("DB_PASSWORD"))输出None,但.env文件里明明写了DB_PASSWORD=secret123 - 真正起作用的是
load_dotenv(),它把文件内容解析后注入os.environ - 默认行为是「跳过已存在的变量」,所以如果系统里已有
ENV=prod,而.env写了ENV=dev,最终生效的仍是prod
load_dotenv() 的路径和覆盖逻辑必须显式控制
它默认只在当前工作目录(os.getcwd())下找 .env,不会向上递归查找,也不会自动识别项目根目录。如果你在子目录运行脚本,大概率加载失败。
- 推荐做法:用
pathlib.Path(__file__).parent / ".env"显式指定相对于当前文件的路径 - 要强制覆盖已有变量,必须传
override=True:load_dotenv(override=True) - 路径不存在时默认静默失败,建议加判断:
if not dotenv_path.exists(): raise FileNotFoundError(f"Missing {dotenv_path}") - 不推荐依赖
find_dotenv()—— 它会从当前路径逐级向上找,行为不可控,CI/CD 中容易误加载上级目录的.env
敏感变量不要硬编码,但也不要全扔进 .env
.env 文件本质是明文,适合本地开发或受信环境;生产环境应改用系统级环境变量或密钥管理服务。强行把生产数据库密码塞进 .env 并提交到 Git,等于裸奔。
- 务必把
.env加入.gitignore,检查git status是否显示它为未跟踪文件 - 不同环境用不同文件(如
.env.dev、.env.prod),通过load_dotenv(".env.dev")显式加载 -
python-dotenv不支持变量插值(如BASE_URL=https://api.example.com+USER_URL=${BASE_URL}/user),需要额外用dotenv_values()手动解析再拼接 - 类型全是字符串,数值或布尔需自行转换:
DEBUG = os.getenv("DEBUG", "false").lower() == "true"
最容易被忽略的一点:加载时机。必须在任何依赖这些变量的模块导入前调用 load_dotenv(),否则像 Django 或 SQLAlchemy 这类框架启动时就读取了环境变量,后续再加载已经晚了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











