第三章:虚拟环境与依赖管理
说到Python开发,虚拟环境和依赖管理是绕不开的话题。我刚开始写Python那会儿,经常遇到「这个项目要Django 2.2,那个项目要Django 3.0」的尴尬局面。后来才明白,虚拟环境就是给每个项目一个独立的小房间,互不干扰。
3.1 为什么需要虚拟环境?
说白了,Python的包管理默认是全局安装。你装一个包,所有项目都能用。但问题来了——项目A需要requests 2.25,项目B需要requests 2.26,你装哪个?
虚拟环境就是解决这个问题的。它给每个项目创建独立的Python解释器和包目录。你在项目A里装什么,都不会影响项目B。
核心概念:虚拟环境 = 隔离的Python运行环境。每个环境有自己的site-packages目录,互不干扰。
3.2 venv:Python自带的轻量级方案
从Python 3.3开始,venv就内置了。不需要额外安装,直接用。
# 创建虚拟环境
python -m venv myenv
# 激活(Windows)
myenv\Scripts\activate
# 激活(macOS/Linux)
source myenv/bin/activate
# 退出
deactivate
我个人习惯用venv做快速原型开发。它够轻量,没什么花哨功能。但有个缺点——你没法自动记录依赖版本。每次都要手动pip freeze > requirements.txt。
小技巧:我一般会在项目根目录建一个.venv文件夹,然后加到.gitignore里。这样团队其他人拉代码后,自己创建虚拟环境就行。
3.3 requirements.txt:最朴素的依赖清单
requirements.txt就是个文本文件,一行一个包名。格式很简单:
# 指定版本
Django==3.2.18
requests==2.28.2
# 版本范围
numpy>=1.21.0,<1.24.0
# 从GitHub安装
git+https://github.com/psf/requests.git@v2.28.2
生成方式:
# 导出当前环境所有包
pip freeze > requirements.txt
# 安装依赖
pip install -r requirements.txt
嗯,这里要注意。pip freeze会把所有包都列出来,包括那些间接依赖。我曾经遇到过一个问题——同事的requirements.txt里有个包版本写死了,结果新环境装不上。后来我改用pip list --format=freeze,只保留直接依赖。
3.4 pipenv:更现代的依赖管理
pipenv是Kenneth Reitz(就是requests库的作者)开发的。它把虚拟环境和依赖管理合二为一,还引入了Pipfile和Pipfile.lock。
# 安装pipenv
pip install pipenv
# 创建虚拟环境并安装依赖
pipenv install requests
# 安装开发依赖
pipenv install --dev pytest
# 激活虚拟环境
pipenv shell
# 生成Pipfile.lock
pipenv lock
Pipfile长这样:
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
requests = "*"
Django = "==3.2.18"
[dev-packages]
pytest = "*"
[requires]
python_version = "3.9"
说实话,pipenv刚出来时我挺喜欢的。但用久了发现一个问题——它有时候锁依赖锁得太死,升级一个包要折腾半天。而且pipenv的解析速度,嗯,有点慢。
避坑指南:我曾经在一个大项目里用pipenv,结果lock文件解析了快10分钟。后来发现是某个包的依赖树太复杂。建议项目依赖超过50个时,慎重考虑pipenv。
3.5 poetry:后起之秀
poetry是目前社区比较推崇的方案。它解决了pipenv的一些痛点,解析速度快,而且支持构建和发布包。
# 安装poetry
curl -sSL https://install.python-poetry.org | python3 -
# 初始化项目
poetry new myproject
# 添加依赖
poetry add requests
# 添加开发依赖
poetry add --dev pytest
# 安装所有依赖
poetry install
# 生成requirements.txt(如果需要)
poetry export -f requirements.txt --output requirements.txt
poetry的pyproject.toml配置:
[tool.poetry]
name = "myproject"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
[tool.poetry.dependencies]
python = "^3.9"
requests = "^2.28.0"
Django = "3.2.18"
[tool.poetry.dev-dependencies]
pytest = "^7.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
我个人现在主要用poetry。为什么?因为它快,而且pyproject.toml是Python社区的标准配置格式。你想想看,以后所有Python工具都用同一个配置文件,多省心。
3.6 三种方案对比
| 特性 | venv + requirements.txt | pipenv | poetry |
|---|---|---|---|
| 配置格式 | requirements.txt | Pipfile + Pipfile.lock | pyproject.toml + poetry.lock |
| 依赖解析 | 手动管理 | 自动(较慢) | 自动(较快) |
| 虚拟环境管理 | 手动 | 自动 | 自动 |
| 包发布 | 不支持 | 不支持 | 支持 |
| 学习成本 | 低 | 中 | 中高 |
| 适用场景 | 小项目、快速原型 | 中等项目 | 中大型项目、库开发 |
3.7 我的建议
如果你是新手,从venv + requirements.txt开始。够用,而且能让你理解依赖管理的本质。
如果你在团队协作项目里,试试poetry。它的lock文件能保证所有人用完全一样的依赖版本,避免「我这边能跑,你那边报错」的尴尬。
至于pipenv...嗯,除非你特别喜欢它的工作流,否则我建议跳过。不是它不好,而是poetry做得更好。
最后一个小建议:不管用哪种方案,记得把虚拟环境目录加到.gitignore里。另外,lock文件一定要提交到版本控制。这样别人拉代码后,能还原出完全一样的环境。
好了,虚拟环境和依赖管理就聊到这儿。下一章我们聊聊Docker容器化——那又是另一个有意思的话题了。