Post

Python Virtual Environments

整理 Python 虚拟环境的用途,以及 venv、Conda、uv 三种工具的环境创建、包管理与项目依赖管理方法

Python Virtual Environments

不同的项目往往依赖同一个包的不同版本,全部装进系统的 Python 会互相冲突。虚拟环境为每个项目提供一套独立的解释器和包目录,互不影响,删除时也只需要删掉对应的目录

Ubuntu 23.04 起,系统自带的pip直接安装包时会报externally-managed-environment错误,这是为了防止破坏系统自身依赖的 Python 包,正确的做法就是在虚拟环境中安装

工具对比

工具管理 Python 版本包的来源特点
venv不能,使用系统已有的 PythonPyPI标准库自带,不需要额外安装,功能最基础
conda能Conda 频道,也可以用pip可以安装 CUDA、编译器等非 Python 依赖,环境集中存放
uv能PyPI速度快,带锁文件的项目依赖管理,兼容pip的用法

venv

venv是 Python 标准库自带的虚拟环境模块,环境就是项目目录下的一个文件夹,习惯上命名为.venv

1
sudo apt install -y python3-venv
1
python3 -m venv .venv
1
2
source .venv/bin/activate
deactivate

激活后终端提示符前会出现(.venv),此时的python和pip都指向环境内部,安装的包只存在于该环境中

1
2
pip install numpy
pip list
1
pip freeze > requirements.txt
1
pip install -r requirements.txt
1
rm -rf .venv

虚拟环境中保存的是绝对路径,移动或重命名项目目录后环境会失效,需要删除后重新创建。.venv不应提交到代码仓库,提交requirements.txt即可

Conda

conda是anaconda发行版中的包管理器,用于安装、更新、卸载软件包,以及创建和管理不同的Python环境。除Anaconda外,也可以使用默认conda-forge频道的Miniforge发行版(Anaconda的defaults频道对组织用户有商业授权限制)

环境管理

1
conda create --name env
1
conda create --name env python=3.12
1
conda env create -f conda_environment.yaml
1
conda env list
1
2
conda activate env
conda deactivate
1
conda create --name env_copy --clone env
1
2
conda env export --name env > conda_environment.yaml
conda env export --name env --from-history > conda_environment.yaml

直接导出会包含所有依赖及其构建编号,只能在相同的操作系统上还原;加上--from-history只导出手动安装过的包,适合跨平台共享

1
conda env remove --name env
1
conda config --set auto_activate_base false

包管理

以下命令作用于当前激活的环境,也可以用--name env指定环境

1
2
3
conda install numpy
conda install numpy=1.26
conda install -c conda-forge opencv
1
2
conda list
conda search numpy
1
2
conda update numpy
conda remove numpy
1
conda clean --all

conda环境中可以使用pip安装conda频道中没有的包,但应先用conda安装能安装的包,最后再使用pip,否则conda之后的依赖解析可能会破坏pip安装的包

优化指令

显示配置的来源文件及其内容

1
conda config --show-sources

与conda config --show channels相比,能查看当前环境所读取的配置文件信息

使用 libmamba 求解器

conda 23.10 起默认使用libmamba求解器(即mamba的求解器),无需另外安装mamba即可获得更快的依赖解析。可通过以下命令确认

1
conda config --show solver

如需使用mamba命令本身,官方推荐直接安装Miniforge发行版(自带conda-forge与mamba),不建议在 Anaconda 的base环境中用conda install mamba混装conda-forge的包。mamba的大部分命令与conda相同,但 2.x 版本在部分子命令上存在差异

uv

uv是用 Rust 编写的 Python 包与项目管理工具,把pip、venv、Python 版本管理和依赖锁定合并到了一个命令里,安装包的速度比pip快很多

安装

1
curl -LsSf https://astral.sh/uv/install.sh | sh

安装到~/.local/bin,重新打开终端后生效

1
uv self update

管理 Python 版本

uv可以自行下载并管理多个 Python 版本,不依赖系统自带的 Python,也不需要sudo

1
uv python list
1
uv python install 3.12
1
uv python pin 3.12

创建环境或运行项目时,所需的 Python 版本不存在会自动下载

虚拟环境与 pip 接口

uv pip的用法与pip基本一致,适合在已有的requirements.txt工作流中直接替换

1
2
uv venv
uv venv --python 3.12
1
source .venv/bin/activate
1
2
uv pip install numpy
uv pip install -r requirements.txt
1
2
uv pip list
uv pip freeze > requirements.txt

uv pip默认操作当前目录下的.venv,不激活环境也可以使用。uv venv创建的环境中没有pip命令,安装包一律使用uv pip

项目管理

uv推荐的用法是把依赖写进pyproject.toml,由它负责创建环境、解析依赖和生成锁文件,不需要手动激活环境

1
2
uv init --app --no-package demo
cd demo

--app --no-package创建的是只有一个main.py的脚本项目;不加参数时会生成带src/目录、可以被安装的包

文件作用
pyproject.toml项目信息和依赖列表
uv.lock锁文件,记录每个依赖解析出的确切版本,应提交到代码仓库
.python-version项目使用的 Python 版本
.venv虚拟环境,首次运行时自动创建,不提交到代码仓库
1
2
3
uv add numpy
uv add "numpy>=2.0"
uv add --dev pytest
1
uv remove numpy
1
2
uv run main.py
uv run pytest

uv run运行前会检查环境与锁文件是否一致,不一致时自动同步,因此不需要激活环境

1
uv sync
1
uv lock --upgrade
1
uv tree
1
uv export --format requirements-txt -o requirements.txt

运行命令行工具

ruff、black这类命令行工具不属于某个项目,可以用uvx在临时环境中直接运行,不污染任何环境

1
uvx ruff check
1
2
uv tool install ruff
uv tool list

镜像与缓存

下载速度慢时可以配置 PyPI 镜像,对所有项目生效

1
2
3
[[index]]
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
default = true

只想对单个项目生效时,在pyproject.toml中把[[index]]写成[[tool.uv.index]]

uv下载过的包保存在全局缓存中,多个环境通过链接共用同一份文件,不会重复占用磁盘

1
2
uv cache dir
uv cache clean

如何选择

  • 只是临时装几个包、不想装额外的工具,使用venv
  • 需要 CUDA、OpenCV 等带有非 Python 依赖的包,或者要与他人共享完整的运行环境,使用conda
  • 新建的纯 Python 项目使用uv,依赖有锁文件,换一台机器执行uv sync就能得到相同的环境
  • 不要在同一个环境里混用多种工具安装包,conda环境中确实需要pip时放在最后安装
This post is licensed under CC BY 4.0 by the author.