在Python项目开发中,硬编码敏感配置信息(数据库密码、API密钥、Token)、区分开发/生产环境配置 是非常常见的需求,也是项目工程化的核心要点。直接将这类信息写在代码里,不仅存在极高的安全泄露风险,还会导致项目部署时需要频繁修改代码,灵活性较差。
python-dotenv 是Python生态中主流的环境变量管理工具,完美解决了上述问题。它可以从专门的环境配置文件中读取配置项并注入到系统环境变量中,实现「配置与代码完全解耦」,让项目配置管理更安全、更灵活、更规范。
python-dotenv 当前的稳定版本是:1.2.1
安装 python-dotenv
python-dotenv 支持pip直接安装,执行如下命令即可:
pip install python-dotenv==1.2.1
版本验证:安装完成后,执行 pip show python-dotenv,查看 Version 字段为 1.2.1 即安装成功。
文件规范
2.1 核心配置文件:.env 文件
python-dotenv 的核心是 .env 文件 ,这是一个存放项目所有环境变量的纯文本文件,所有需要动态配置的信息都写在这里。
- 存放位置:推荐放在Python项目的根目录(和项目的主入口文件同级),这是python-dotenv的默认读取路径,无需额外配置路径。
- 配置项采用
KEY=VALUE 的键值对格式,等号左右不要加空格 - 字符串类型的值可以不用加引号,带空格的字符串建议用双引号包裹
- 支持换行符、特殊字符,无需额外转义(特殊场景除外)
2.2 核心忽略文件:.gitignore
.env 文件中存储的都是敏感信息和项目配置,一般不能提交到Git/Gitee等代码仓库!
解决方案:在项目根目录的 .gitignore 文件中,添加一行 .env,Git就会自动忽略该文件,杜绝敏感信息泄露的风险。
# 项目通用忽略项__pycache__/*.py[cod]# 环境配置文件(核心忽略项).env
基础核心用法
3.1 编写标准的 .env 配置文件
在你的Python项目根目录,新建一个无文件名、后缀为env的文件(即 .env),写入如下示例配置,涵盖开发中最常见的配置场景:
# 数据库配置(核心敏感信息)DB_HOST=127.0.0.1DB_PORT=3306DB_USER=rootDB_PASSWORD=MyDbPass123!DB_NAME=my_python_project# API密钥与TokenAPI_KEY=afd9s7f9a8s7df9a8s7d9f8a7s9df87JWT_SECRET=my_jwt_secret_key_2026_python# 项目运行配置ENVIRONMENT=development # development=开发环境,production=生产环境DEBUG=TrueAPP_PORT=8000MAX_CONNECTIONS=50# 带空格的字符串配置(建议双引号包裹)APP_TITLE="Python Dotenv 实战项目"ADMIN_USER="张三 管理员"
3.2 加载 .env 文件并读取环境变量
方案一:使用 load_dotenv() 核心函数
核心逻辑:load_dotenv() 会自动读取项目根目录的 .env 文件,将其中的所有配置项注入到系统的环境变量中,之后就可以通过Python内置的 os 模块的 os.getenv() 方法读取配置项。
完整示例代码(新建 main.py,和 .env 同级):
# 1. 导入核心依赖import osfrom dotenv import load_dotenv# 2. 加载.env文件,将配置注入系统环境变量# 执行后,.env中的配置就全部存入 os.environ 字典中了load_dotenv()# 3. 读取环境变量 - 核心方法:os.getenv("配置项KEY", 默认值)# 语法:os.getenv(键名, default=None),推荐带默认值,防止配置项缺失时报错if __name__ == '__main__':# 读取数据库配置 db_host = os.getenv("DB_HOST") db_port = os.getenv("DB_PORT") db_password = os.getenv("DB_PASSWORD") db_name = os.getenv("DB_NAME")# 读取布尔值、数字类型(注意:读取的所有值默认都是字符串类型) debug_mode = os.getenv("DEBUG", "False") == "True" app_port = int(os.getenv("APP_PORT", 8000)) max_conn = int(os.getenv("MAX_CONNECTIONS", 30))# 读取带空格的字符串 app_title = os.getenv("APP_TITLE") admin_user = os.getenv("ADMIN_USER")# 打印验证 print("===== 项目配置信息 =====") print(f"数据库地址: {db_host}:{db_port}") print(f"数据库密码: {db_password}") print(f"数据库名称: {db_name}") print(f"是否调试模式: {debug_mode}") print(f"项目端口: {app_port}") print(f"项目标题: {app_title}") print(f"管理员: {admin_user}")
方案二:使用 dotenv_values() 函数
核心逻辑:dotenv_values() 不会修改系统环境变量,而是直接读取 .env 文件并返回一个字典,所有配置项都存在这个字典中,适合不想污染系统环境变量的场景。
优点:无侵入、不修改系统环境变量;缺点:需要维护一个字典对象,多模块共享配置略繁琐。
from dotenv import dotenv_values# 读取.env文件,返回字典,不注入系统环境变量config = dotenv_values(".env")if __name__ == '__main__':# 像操作普通字典一样读取配置 print(config["DB_USER"]) print(config["API_KEY"]) print(config["ENVIRONMENT"])
3.3 注意事项
读取的所有值默认是字符串类型:.env 中无论写的是数字、布尔值(True/False),通过 os.getenv() 读取后都是字符串,需要手动做类型转换(如 int()、bool() 判断),这是python-dotenv的特性,也是最容易踩坑的点。
os.getenv() 一定要加默认值:推荐写法 os.getenv("KEY", 默认值),如果配置项在 .env 中缺失,会返回默认值,避免抛出 None 导致后续代码报错。
load_dotenv() 执行时机:建议在项目的入口文件最顶部执行,确保整个项目运行时都能读取到环境变量。
高级进阶用法
针对实际开发中的复杂场景(多环境切换、自定义配置文件路径、中文配置、优先级控制),python-dotenv 都提供了较好的解决方案。
4.1 场景一:区分「开发环境/生产环境」- 多环境配置文件切换
实际开发中,开发环境(development) 和 生产环境(production) 的配置肯定是不同的(比如开发环境用本地数据库,生产环境用线上数据库),最规范的做法是创建多个环境配置文件:
实现步骤
项目根目录新建两个配置文件:.env.dev(开发配置)、.env.prod(生产配置),分别写入对应环境的配置;
通过 load_dotenv() 的 dotenv_path 参数指定加载的配置文件路径;
可以通过系统环境变量控制加载哪个配置文件,实现「无代码修改切换环境」。
示例代码(自动切换环境):
import osfrom dotenv import load_dotenv# 定义要加载的环境(可通过系统环境变量传入,无需修改代码)env_type = os.getenv("RUN_ENV", "dev") # 默认加载开发环境# 根据环境类型加载对应的配置文件if env_type == "dev": load_dotenv(dotenv_path=".env.dev") # 加载开发环境配置elif env_type == "prod": load_dotenv(dotenv_path=".env.prod") # 加载生产环境配置elif env_type == "test": load_dotenv(dotenv_path=".env.test") # 加载测试环境配置# 后续读取配置的方式不变print("当前运行环境:", os.getenv("ENVIRONMENT"))print("数据库地址:", os.getenv("DB_HOST"))
4.2 场景二:自定义 .env 文件路径(非根目录)
如果你的 .env 文件不在项目根目录(比如放在 config/ 子目录下),无需移动文件,只需在 load_dotenv() 中通过 dotenv_path 指定绝对路径/相对路径即可。
示例:配置文件路径为 项目根目录/config/.env
import osfrom dotenv import load_dotenv# 方式1:相对路径(推荐,项目移植性更强)load_dotenv(dotenv_path="./config/.env")# 方式2:绝对路径(精准,适合部署环境)# config_path = os.path.join(os.path.dirname(__file__), "config", ".env")# load_dotenv(dotenv_path=config_path)# 读取配置print(os.getenv("API_KEY"))
4.3 场景三:环境变量的「优先级控制」(系统环境变量 > .env 文件)
核心规则(官方设计,非常重要):当系统环境中已存在同名的环境变量时,python-dotenv不会覆盖它!
举个例子:如果你的操作系统中已经配置了 DB_HOST=192.168.1.100,而 .env 文件中配置的是 DB_HOST=127.0.0.1,执行 load_dotenv() 后,通过 os.getenv("DB_HOST") 读取到的是系统环境的 192.168.1.100,而非 .env 中的值。
这个特性的核心价值:线上部署时,可以通过系统环境变量覆盖配置,无需修改项目的 .env 文件,极大提升部署灵活性。
如果需要强制用 .env 文件的配置覆盖系统环境变量,只需给 load_dotenv() 传入 override=True 参数:
# 强制覆盖:.env 文件配置 > 系统环境变量load_dotenv(override=True)
4.4 场景四:读取中文配置项
python-dotenv 1.2.1 对中文编码做了兼容,.env 文件中直接写入中文配置项即可,无需额外设置编码格式,读取时不会出现乱码问题。
示例:
# .env 中写入中文APP_DESC=这是一个使用python-dotenv的中文项目CONTACT_EMAIL=python_dev@163.com
读取代码:
import osfrom dotenv import load_dotenvload_dotenv()print(os.getenv("APP_DESC")) # 输出:这是一个使用python-dotenv的中文项目
4.5 场景五:配置项封装
在实际的大型项目中,不会在每个模块都写 os.getenv(),而是将所有配置项封装到一个单独的配置模块(比如 config.py)中,统一管理、统一读取,后续所有模块都从这个配置模块导入即可,这是Python项目的标准配置管理规范。
实现步骤
项目根目录新建 config.py 文件(配置封装模块);
在 config.py 中完成 .env 加载和所有配置项的读取、类型转换;
其他业务模块(如 main.py、db.py)直接导入 config.py 中的配置项。
封装后的 config.py示例:
import osfrom dotenv import load_dotenv# 加载.env文件,全局生效load_dotenv()# ===================== 数据库配置 =====================DB_HOST = os.getenv("DB_HOST", "127.0.0.1")DB_PORT = os.getenv("DB_PORT", "3306")DB_USER = os.getenv("DB_USER", "root")DB_PASSWORD = os.getenv("DB_PASSWORD", "")DB_NAME = os.getenv("DB_NAME", "default_db")# ===================== 项目运行配置 =====================ENVIRONMENT = os.getenv("ENVIRONMENT", "development")DEBUG = os.getenv("DEBUG", "False").upper() == "TRUE"APP_PORT = int(os.getenv("APP_PORT", 8000))MAX_CONNECTIONS = int(os.getenv("MAX_CONNECTIONS", 50))# ===================== 密钥与Token =====================API_KEY = os.getenv("API_KEY", "")JWT_SECRET = os.getenv("JWT_SECRET", "")# ===================== 项目信息 =====================APP_TITLE = os.getenv("APP_TITLE", "Python Project")ADMIN_USER = os.getenv("ADMIN_USER", "admin")
业务模块 main.py 中使用配置(示例):
# 直接从配置模块导入,无需再写os.getenv,代码更简洁from config import DB_HOST, DB_PASSWORD, DEBUG, APP_PORT, APP_TITLEif __name__ == '__main__': print(f"项目标题: {APP_TITLE}") print(f"数据库地址: {DB_HOST}") print(f"是否调试模式: {DEBUG}") print(f"运行端口: {APP_PORT}")
五、常见问题
问题1:执行代码后,读取的配置项都是 None
可能的原因:
load_dotenv() 函数未执行(核心步骤缺失);.env 文件的路径不对,load_dotenv() 找不到配置文件;- 配置项的 KEY大小写不一致(比如
.env 中是 DB_HOST,代码中写 db_host)。
可以考虑的方法::
- 确认代码中第一时间执行了
load_dotenv(); - 确认
.env 和入口文件同级,或通过 dotenv_path 指定正确路径;
问题2:布尔值配置(DEBUG=True)读取后判断失效
可能的原因:所有从 .env 读取的配置项都是字符串类型,os.getenv("DEBUG") 返回的是字符串 "True",而非布尔值 True,直接用 if DEBUG: 判断永远为True。
可以考虑的方法::
手动做布尔值转换,推荐两种写法:
# 写法1(推荐)DEBUG = os.getenv("DEBUG", "False") == "True"# 写法2(更健壮,兼容大小写)DEBUG = os.getenv("DEBUG", "False").upper() == "TRUE"
问题3:.env 文件提交到了Git仓库
可能的原因:忘记在 .gitignore 中添加 .env 忽略规则。
可以考虑的方法:
- 如果已经提交到仓库,执行
git rm --cached .env 移除追踪,再提交; - 重新生成敏感配置(如API密钥、数据库密码),防止泄露。
六、总结
- python-dotenv 是Python项目的环境管理工具,核心作用是「配置与代码解耦」,杜绝硬编码敏感信息,提升项目安全性和可维护性;
- 使用流程:创建
.env 配置文件 → 执行 load_dotenv() 加载配置 → 通过 os.getenv() 读取配置; - 所有配置项读取后默认是字符串类型,需要手动做类型转换(数字、布尔值);
- 系统环境变量的优先级高于
.env 文件,可通过 override=True 强制覆盖。