Python 依赖管理实践:虚拟环境、锁定文件与容器构建
一、为什么需要虚拟环境
Python 的依赖默认安装在全局解释器里,两个项目如果依赖同一个包的不同版本,就会互相破坏。虚拟环境为每个项目提供独立的 site-packages,是最低成本的隔离手段。
常见问题是「本地能跑、服务器不行」,多数时候不是代码问题,而是依赖版本、Python 版本或系统库不一致。
二、venv 与 conda 的选择
标准库自带的 venv 足够覆盖大多数纯 Python 项目:
python3 -m venv .venv
source .venv/bin/activate
conda 更适合需要科学计算栈、或需要管理非 Python 依赖(如 CUDA、编译工具链)的场景。如果项目只依赖 pip 包,用 venv 就够了,不必引入额外工具。
三、锁定依赖,而不是只写 requirements.txt
pip freeze > requirements.txt 会把当前环境的全部包和精确版本写入,但它是「结果快照」,不适合直接当作依赖声明。更合理的方式是分层:
pyproject.toml或requirements.in:声明直接依赖与版本范围;requirements.txt或uv.lock:锁定完整的解析结果,用于可复现安装。
这样升级依赖时有明确的入口,而不是在一个几百行的 txt 里手工改。
四、开发依赖与运行依赖分开
测试、格式化、类型检查这些只在开发期使用的包,不应进入生产镜像。常见做法是分成多个文件:
requirements.txt # 运行依赖
requirements-dev.txt # 开发依赖,通过 -r requirements.txt 继承
或者在 pyproject.toml 中用 optional-dependencies 分组,安装时按需指定。
五、Docker 中的最佳实践
容器构建时,先复制依赖声明并安装,再复制源码,可以最大化利用构建缓存:
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
同时使用 --no-cache-dir 避免把 pip 缓存打进镜像;生产镜像里不要激活虚拟环境后再装包,直接装到系统环境或用多阶段构建把虚拟环境复制过去都可以,关键是不要在运行时依赖开发工具。
六、常见坑
- 忘记激活环境:
which python确认当前解释器路径,比反复猜更有效; - pth 文件污染:全局 site-packages 里的 .pth 会让虚拟环境「看到」外部包,排查时可用
python -c "import sys; print(sys.path)"检查; - 系统包管理器冲突:不要用系统 pip 安装项目依赖,容易破坏系统工具;
- 锁文件未提交:锁文件必须进版本库,否则可复现性无从谈起。
依赖管理没有银弹,但「声明与锁定分离、开发与运行分离、构建与运行分离」这三条原则适用于几乎所有 Python 项目。
- 点赞
- 收藏
- 关注作者
评论(0)