Python入门:虚拟环境与pip包管理

不同项目依赖不同版本的库,如果全部装在系统 Python 下迟早会冲突。虚拟环境就是解决这个问题的标准方案——每个项目一个独立的 Python 环境,互不干扰。

什么是虚拟环境

虚拟环境本质上是一个目录,里面包含了独立的 Python 解释器和 site-packages。在虚拟环境中安装的包不会影响系统 Python,也不会影响其他虚拟环境。

Python 3.3+ 内置了 venv 模块,不需要额外安装任何东西。

创建和激活虚拟环境

创建

# 在当前目录下创建名为 venv 的虚拟环境
python -m venv venv

# 也可以指定其他名称
python -m venv .env
python -m venv myproject_env

执行后会在当前目录生成一个 venv 文件夹,里面包含 bin/(Linux/Mac)或 Scripts/(Windows)目录和独立的 lib/ 目录。

激活

# Linux / macOS
source venv/bin/activate

# Windows CMD
venv\Scripts\activate.bat

# Windows PowerShell
venv\Scripts\Activate.ps1

激活后,终端提示符前面会出现 (venv) 标识,此时 pythonpip 命令都指向虚拟环境中的版本。

退出

deactivate

pip 包管理

安装包

# 安装最新版
pip install requests

# 安装指定版本
pip install requests==2.25.0

# 安装最低版本
pip install "requests>=2.20"

# 一次安装多个包
pip install flask redis celery

查看已安装的包

# 列出所有已安装的包
pip list

# 查看某个包的详细信息
pip show requests

导出和恢复依赖

这是团队协作中最重要的操作:

# 导出当前环境的所有依赖到 requirements.txt
pip freeze > requirements.txt

# 根据 requirements.txt 安装所有依赖
pip install -r requirements.txt

requirements.txt 的内容大致如下:

certifi==2020.12.5
chardet==4.0.0
idna==2.10
requests==2.25.1
urllib3==1.26.2

建议把 requirements.txt 纳入版本控制,但不要把 venv 目录提交到 Git——在 .gitignore 中加入 venv/ 即可。

卸载包

pip uninstall requests

升级包

# 升级指定包
pip install --upgrade requests

# 升级 pip 自身
pip install --upgrade pip

常见问题

pip install 速度慢怎么办?

使用国内镜像源:

# 临时使用
pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

# 永久配置(Linux/macOS)
mkdir -p ~/.pip
cat > ~/.pip/pip.conf << EOF
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
trusted-host = pypi.tuna.tsinghua.edu.cn
EOF

装了包但 import 报错?

大概率是没有激活虚拟环境,或者 pip 和 python 不是同一个环境的。用 which pythonwhich pip 确认路径是否一致。

多个 Python 版本共存时 venv 用的是哪个?

python -m venv 用的是哪个 python,虚拟环境里就是哪个版本。如果系统同时有 Python 3.7 和 3.9,可以用 python3.9 -m venv venv 来指定版本。

项目推荐的工作流

  1. 进入项目目录,创建虚拟环境:python -m venv venv
  2. 激活虚拟环境:source venv/bin/activate
  3. 安装依赖:pip install -r requirements.txt
  4. 开发完成后导出依赖:pip freeze > requirements.txt
  5. 提交 requirements.txt 到 Git

养成这个习惯,就不会再遇到"在我机器上能跑"的尴尬了。