第三章:虚拟环境与依赖管理

说到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容器化——那又是另一个有意思的话题了。