分成如下几个部分:

  • pip:包下载安装
  • venv:虚拟环境管理
  • conda:包下载安装和 conda 环境管理

这些内容在不同的系统(Windows/Linux)中的实现细节各有不同,在不同的 shell(pwsh/bash/fish)中,对应的脚本实现也有差异,下面以 Linux + bash 为主,也会考虑 Windows + pwsh 的情况。

为了便于区分,本文中的虚拟环境特指使用 venv 创建的虚拟环境,conda 创建的虚拟环境则称为 conda 环境

pip

基本使用

使用 pip 可以安装 Python 包,常见形式为

1
pip install <package_name>

例如安装进度条工具 tqdm

1
pip install tqdm

pip 会自动处理包的版本要求和依赖关系,依赖关系在不同系统下可能存在差异,例如:

  • 在 Linux 上只会安装 tqdm 自身;
  • 在 Windows 上会自动安装两个包:colorama, tqdm,前者是 tqdm 的依赖。

列出当前所有的包

1
pip list

安装位置

pip 安装的包默认会存放在特定位置的 site-packages/ 目录(位置和当前处于全局,还是在虚拟环境 / conda 环境中有关),可以使用下面的命令查看这个文件夹

1
python -m site

其中的内容形如

1
2
3
4
5
site-packages/
|- pip/
|- pip-23.2.1.dist-info/
|- tqdm/
|- tqdm-4.67.1.dist-info/

这里需要解释一下:

  • pip 本质上仍然是一个 Python 包,同名的可执行文件只是调用入口,实际会调用 site-packages/pip/ 目录中的内容。
  • pip-23.2.1.dist-info/ 目录用于存储与安装的 pip 包版本相关的元数据。
  • tqdm 还提供了一个可执行文件,被添加到对应的可执行文件路径,可以在命令行中直接调用。

pip 配置

pip 可以切换镜像源,临时修改可以通过添加 -i 选项实现,例如

1
pip install -i https://pypi.mirrors.ustc.edu.cn/simple numpy

持续性修改

1
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/simple

在 Linux 中,这里实质会改动配置文件 ~/.config/pip/pip.conf

1
2
[global]
index-url = https://mirrors.ustc.edu.cn/pypi/simple

安装途径

除了通过 PyPi 进行安装之外,pip 还支持很多安装方式,包括:

  • 通过 Github 仓库安装:pip install git+https://github.com/user/repo.git;(要求该仓库的内容符合 Python 包的格式标准,例如有 setup.py 文件等)
  • 通过 .tar.gz 或 .zip 文件进行源码安装:pip install /path/to/package.tar.gz;(支持直接使用网络上的压缩包)(要求这些压缩包中的内容符合 Python 包的格式标准)
  • 使用 Python 设计的 wheel 文件(后缀 .whl)进行模块的安装,wheel 文件是被设计替代源码压缩包的二进制文件,它相比于压缩包的优势是已经包含了所有编译好的二进制文件,因此安装速度更快,并且可以避免一些编译问题。

venv

venv 虚拟环境是 Python 提供的一个工具,用于创建隔离的环境来管理不同项目的依赖关系,每一个虚拟环境实际存储于一个目录下,但是可以在任何其它位置激活和使用这个虚拟环境。

在Linux中即使自带 Python,也可能不包括 venv,需要使用 pip 额外下载安装 python3-venv。

创建虚拟环境

在当前目录下创建一个名为 myenv 的虚拟环境

1
python -m venv myenv

按照惯例,虚拟环境的文件夹通常被设置为 .venvvenv

这个命令会在当前目录下创建一组文件和子目录,通常包括以下几个关键部分:

  • bin/:包含一组独立的 Python 解释器(可执行文件)和 pip 以及命令脚本(针对各个shell);
  • lib/pythonX.Y/site-packages/:存放该虚拟环境下所有的 Python 库,初始情况下只有 pip;
  • include/:包含C语言头文件,用于在该虚拟环境中进行扩展编译。
  • pyvenv.cfg:包含虚拟环境的配置信息(如 Python 版本信息,创建时的命令)。

这里呈现的是 Linux 中的目录结构,对于 Windows 存在一些细微区别。

虚拟环境所涉及的命令脚本实际上分别提供了 bash,cmd 和 pwsh 这几个版本,下面的讨论主要以 Linux 为例。

pyvenv.cfg大致包括如下内容:

1
2
3
4
5
home = /home/xxx/miniconda3/bin
include-system-site-packages = false
version = 3.12.1
executable = /home/xxx/miniconda3/bin/python3.12
command = /home/xxx/miniconda3/bin/python -m venv /home/xxx/test/myvenv

激活、退出虚拟环境

执行激活脚本可以激活(当前目录下的)虚拟环境,例如

1
2
3
4
5
6
7
8
# windows pwsh
.\myenv\Scripts\Activate(.ps1)

# linux bash
source myenv/bin/activate

# linux fish
source myenv/bin/activate.fish

说明:

  • 在 Linux 中,不能直接执行对应脚本(没有执行权限),而且只有通过 source(或 .)启动后才会对当前进程有效;(在 Windows 中不存在这种问题)
  • 也可以激活和使用其它目录下的虚拟环境,只需要相应调整命令中的路径即可。

激活环境之后,shell 的命令行提示符通常会变化,自动提示当前虚拟环境的名称,例如

1
(myenv) user@xxx$

如果采用默认名称 .venvvenv,在 Windows 上的命令提示符可能会自动替换为显示当前文件夹名称。

使用 deactivate 命令可以退出当前的虚拟环境

1
deactivate

deactivate 可能是通过单独的 shell 脚本提供,也可能是通过定义的 shell 函数提供。

激活虚拟环境实际上就是调用了对应目录中的激活脚本,执行了一些简单操作,主要包括:

  • 修改环境变量 PATH,将当前目录添加到环境遍历路径的开头,确保 pythonpip 等命令会优先找到当前虚拟环境中的实例;
  • 修改环境变量 VIRTUAL_ENV 记录当前的虚拟环境;
  • 修改当前 shell 的命令行提示符;(受到 VIRTUAL_ENV_DISABLE_PROMPT 环境变量控制)
  • 将当前环境的 site-packages/ 目录添加到模块搜索路径中,确保可以成功导入当前环境中所安装的包;
  • 提供一个 deactivate 命令,作用就是将 activate 所做的修改撤销。

退出激活环境则是撤销了上述过程的影响。

如果要删除虚拟环境,只需要直接删除虚拟环境对应的目录即可。

虚拟环境导出和恢复

我们可以使用 pip 导出当前虚拟环境的所有依赖,并保存到文件中,方便下次在别的位置安装

1
pip freeze > requirements.txt

可以在其它位置通过该 requirements.txt 文件安装所有的依赖,从而恢复相同的虚拟环境

1
pip install -r requirements.txt

conda

Anaconda 是一个用于科学计算的开源 Python 发行版,集成了包和 conda 环境管理器,包括了很多数据科学中常用的包,特别适合数据科学和机器学习。

与之类似的还有 Miniconda,它和 Anaconda 的主要区别就是:Miniconda 在安装时并没有附带很多科学计算常用的包,因此本身的安装包很小,在使用时需要手动下载,除此之外没什么区别。

Miniconda 默认不包含很多科学计算常用的基础库,有必要在 base 环境中进行下载安装,例如:

  • numpy
  • matplotlib
  • scipy
  • sympy
  • jupyter
1
conda install numpy scipy matplotlib sympy jupyter

安装 Anaconda/Miniconda

Anaconda 的下载和安装都非常简单,只需要按照官网上的步骤进行即可,实践中也可以选择安装 Miniconda 而非 Anaconda,安装包的体积会小很多。

Windows 安装 Miniconda:直接下载安装程序执行即可,注意修改一下安装位置。 安装程序可能会提示是否修改环境变量,可以确定,也可以稍后手动进行,此时需要将一些路径手动到 PATH 中,例如

1
2
3
D:/miniconda3
D:/miniconda3/Scripts
D:/miniconda3/Library/bin

因为 Miniconda 可能含有各种包和软件,包括一些可执行文件,为了避免潜在的版本冲突(比如覆盖了其它在外部单独安装的软件),建议将这几个路径放在 PATH 靠后的位置。

Linux 安装 Miniconda:参考官网给出的安装过程即可

1
2
3
4
mkdir -p ~/miniconda3
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm ~/miniconda3/miniconda.sh

Linux 安装 Anaconda

1
2
3
wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh
bash Anaconda3-2024.06-1-Linux-x86_64.sh
rm Anaconda3-2024.06-1-Linux-x86_64.sh

在安装过程中需要选择安装位置,默认是当前用户的家目录下,将其修改为/opt/anaconda3即可。 安装脚本可能提示自动进行conda init,可以选择确定,也可以稍后手动进行。

conda init

安装完成之后,需要在 shell(bash,fish,pwsh 等)执行初始化命令

1
conda init

这个命令会自动在 shell 的启动脚本中添加一段配置,例如对于 bash,会在 .bashrc 的末尾添加如下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/path/to/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/path/to/anaconda3/etc/profile.d/conda.sh" ]; then
. "/path/to/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/path/to/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<

说明:

  • 如果直接执行 conda init 报错找不到 conda,可以使用 conda 的完整路径来执行,例如

    1
    ~/miniconda3/condabin/conda init bash

  • 执行 conda init 之后,最好重新加载配置文件(source ~/.bashrc)或者退出 shell 重新进入,即可实现在 shell 中自动激活 conda 环境,此时在命令行提示符中通常会显示 (base),这代表已经进入了默认的 base 环境。

在 Windows Powrshell 中,conda init 命令会自动在 Powershell 的配置文件 profile.ps1 中添加以下内容:

1
2
3
4
5
6
#region conda initialize
# !! Contents within this block are managed by 'conda init' !!
If (Test-Path "/path/to/conda.exe") {
(& "/path/to/conda.exe" "shell.powershell" "hook") | Out-String | ?{$_} | Invoke-Expression
}
#endregion

这段命令非常影响启动速度,即使不激活 base 环境,还是有 1s 左右的耗时,因此考虑优化一下。

解读一下这段命令可知,本质就是获取一个字符串然后在pwsh中执行,这个字符串的内容在固定的平台上也是固定的,所以我们可以直接手动执行一次以获取结果

1
(& "/path/to/conda.exe" "shell.powershell" "hook") | Out-String

然后将输出的内容硬编码到 profile.ps1 中,输出内容形如

1
2
3
4
5
6
7
8
9
$Env:CONDA_EXE = "/path/to/conda.exe"
$Env:_CE_M = $null
$Env:_CE_CONDA = $null
$Env:_CONDA_ROOT = "/path/to/miniconda3"
$Env:_CONDA_EXE = "/path/to/conda.exe"
$CondaModuleArgs = @{ChangePs1 = $True}
Import-Module "$Env:_CONDA_ROOT\shell\condabin\Conda.psm1" -ArgumentList $CondaModuleArgs

Remove-Variable CondaModuleArgs

可能还有conda activate base,将其删掉,不用激活环境。

激活、退出 conda 环境

conda 激活指定的 conda 环境(缺省环境名时会自动激活 base 环境)

1
2
3
conda activate

conda activate myenv

退出 conda 环境

1
conda deactivate

conda 会通过修改 PATH 以及一些 CONDA_ 开头的环境变量来实现不同环境的切换, 这使得在不同环境中使用 python 命令会指向不同目录下的文件。

除了先执行conda init,再执行conda activate,也可以使用下面的方式进行一次性的配置和环境激活,这对于脚本执行的情况很使用

1
source /opt/anaconda3/etc/profile.d/conda.sh && conda activate base

conda 环境管理

默认情况下,conda 会自动创建一个名为 base 的 conda 环境作为基础,我们也可以创建其它的 conda 环境:

  • 创建一个新的 conda 环境,指定 Python 版本

    1
    conda create --name myenv python=3.12.1

  • 克隆已有的 conda 环境来创建新的 conda 环境

    1
    conda create --name myenv2 --clone myenv

注意:

  • 在创建新的 conda 环境时最好指定 Python 版本,缺省时可能会自动使用最新的 Python 版本;
  • 支持指定 Python 版本是 conda 环境相比于 venv 虚拟环境的一大优势,后者无法改变 Python 版本。
  • 不要尝试升级或降级环境中的 Python 版本,因为所有的包都依赖具体的 Python 版本,应该新建一个 conda 环境;

列出当前的所有 conda 环境

1
conda env list

查看当前 conda 环境的信息

1
conda info

删除 conda 环境的所有包和 conda 环境自身

1
conda remove --name myenv --all

与 venv 虚拟环境不同,conda 环境并不会存放在当前目录中,而是存放在一个全局路径中的单独文件夹中,便于全局使用和版本隔离。 对于 Windows 和 Linux,名为 base 和 myenv 的 conda 环境对应的路径可能是

1
2
3
4
5
6
7
8
9
10
11
# base
D:/miniconda3/

# myenv
D:/miniconda3/envs/myenv/

# base (root)
/opt/anaconda3/

# myenv (user)
/home/user/.conda/envs/myenv/

conda 配置

使用下面的命令可以查看 conda 现有的配置

1
conda config --show

通常不希望登陆时自动激活 base 环境,可以使用下面的命令关闭自动激活行为

1
conda config --set auto_activate_base False

如果网络环境不好,可以添加国内的镜像,例如

1
2
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/

这两个配置实际会存储在用户家目录下的配置文件 ~/.condarc 中,内容如下

1
2
3
4
5
auto_activate_base: false
channels:
- https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
- https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
- defaults

与 pip 不同,conda 的配置文件倒是对 Windows 和 Linux 保持一致。

conda 包管理

下面的操作都是在具体的虚拟环境中进行的,操作并不会影响到其他虚拟环境。

在当前环境中列出已安装的包(与 pip list 的内容并不完全一样)

1
conda list

在conda仓库中查找包

1
conda search package_name

安装包(可以指定包的版本)

1
2
conda install package_name
conda install package_name=1.2.3

更新包

1
conda update package_name

更新所有包(谨慎操作,这可能会破坏不同包之间的版本依赖关系)

1
conda update --all

非常有趣的是,conda updateconda upgrade 是完全一样的。

卸载包

1
conda remove package_name

使用 conda removeconda uninstall 是完全一样的。

清理当前环境中的缓存,以及不再需要的文件和包

1
conda clean --all

conda 环境导出和恢复

下面提供两种 conda 环境迁移的方法。

第一种方法,使用如下命令导出包列表

1
conda list --explicit > spec-list.txt

其中的内容大致为

1
2
3
4
5
6
7
8
# This file may be used to create an environment using:
# $ conda create --name <env> --file <this file>
# platform: win-64
@EXPLICIT
https://repo.anaconda.com/pkgs/main/win-64/blas-1.0-mkl.conda
https://repo.anaconda.com/pkgs/main/win-64/ca-certificates-2024.7.2-haa95532_0.conda
https://repo.anaconda.com/pkgs/main/win-64/icc_rt-2022.1.0-h6049295_2.conda
...

然后在别的位置可以通过 spec-list.txt 文件创建环境

1
conda create --name newenv --file spec-list.txt

第二种方法,使用如下命令导出环境信息

1
conda env export > environment.yml

其中的内容大致为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
name: base
channels:
- defaults
dependencies:
- altgraph=0.17.3=py312haa95532_0
- anyio=4.2.0=py312haa95532_0

...

- zstd=1.5.5=hd43e919_0
- pip:
- dukpy==0.4.0
- mutf8==1.0.6
- you-get==0.4.1718
prefix: D:/anaconda3

然后在别的位置可以通过 environment.yml 文件创建环境

1
conda env create -f environment.yml

两种方式的区别:

  • 第一种方式导出的信息是和平台(操作系统)相关的,因此不能在不同的平台之间迁移;第二种方式则可以跨平台迁移。
  • 第一种方式得到的信息更精确,可以精确复刻虚拟环境;第二种方式得到的信息则比较粗略,因为考虑到不同平台上可能存在的差异。

这两种方式都只是导出了一个信息列表,因此还需要在目标平台上进行联网下载和安装;除此之外,Conda-pack 也是一种环境迁移的方式,并且它是包括二进制文件的,大致相当于直接打包,因此显然需要保证二进制文件在目标平台仍然可以顺利运行,无法跨平台。

conda 底层细节

conda 在管理虚拟环境的过程中,实际上除了修改 PATH 环境变量,还会控制如下几个特殊的环境变量:

  • CONDA_DEFAULT_ENV:表示当前激活的 conda 环境的名称
  • CONDA_EXE:指向 conda 可执行文件的完整路径
  • CONDA_PREFIX:执行当前激活的 conda 环境的路径
  • CONDA_PROMPT_MODIFIER:用于修改命令行提示符的环境变量,通常是环境的名称加括号,例如 (base),并且会出现在命令行提示符的前面
  • CONDA_PYTHON_EXE:指向当前 conda 环境中 Python 解释器的路径
  • CONDA_SHLVL:表示当前激活的 conda 环境的层级(没有激活是为0,激活后变成1,允许嵌套激活)

这些变量都是由 conda 管理的,会影响 conda 和其它工具的行为。

对于 Python 自身来说,实际的运行也会涉及到一些 PYTHON 开头的环境变量,例如 PYTHONPATH

可以使用如下方法查看当前的所有 CONDA 开头的环境变量

1
2
3
4
5
# powershell
Get-ChildItem Env: | Where-Object { $_.Name -like "CONDA*" }

# bash
env | grep '^CONDA'

在完成 conda init 配置,并设置 conda 不自动激活环境时,登陆 shell 时的默认情况通常为

1
2
3
4
5
6
7
8
# Windows(powershell)
CONDA_EXE D:\miniconda3\Scripts\conda.exe
CONDA_PROMPT_MODIFIER False

# Linux(bash)
CONDA_EXE=/home/user/miniconda3/bin/conda
CONDA_SHLVL=0
CONDA_PYTHON_EXE=/home/user/miniconda3/bin/python

这里 Windows(powershell) 和 Linux(bash) 的表现略有不同。手动激活环境(或者设置自动激活环境),相关的环境变量就会变为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Windows(powershell)
CONDA_DEFAULT_ENV base
CONDA_EXE D:\miniconda3\Scripts\conda.exe
CONDA_PREFIX D:\miniconda3
CONDA_PROMPT_MODIFIER (base)
CONDA_PYTHON_EXE D:\miniconda3\python.exe
CONDA_SHLVL 1

# Linux(bash)
CONDA_EXE=/home/user/miniconda3/bin/conda
CONDA_PREFIX=/home/user/miniconda3
CONDA_PROMPT_MODIFIER=(base)
CONDA_SHLVL=1
CONDA_PYTHON_EXE=/home/user/miniconda3/bin/python
CONDA_DEFAULT_ENV=base

补充

conda 和 pip 混用

对于 Python 来说,conda 可以安装的包的数量还是远没有 pip 那么丰富,有的库(例如 PyTorch)甚至不提供 conda 包,只提供 pip 包,此时我们就面临着在 conda 环境中混合使用 conda 和 pip 的问题。

conda 环境中通常都附带单独的 pip,用 conda 环境中的 pip 安装的包可以在这个 conda 环境中使用。 因此只需要注意必须在激活 conda 环境后使用环境中的 pip,不要使用系统自带的或者 base 环境的 pip。

conda 和 pip 自身都会尝试解决各个包之间的版本要求和依赖关系等,但是显然混用 conda 和 pip 时更容易产生额外的风险。

下面记录一下路径细节:以 Windows 的 miniconda 为例,在 base 环境和 myenv 环境下的安装路径分别为

1
2
3
4
5
# base
D:\miniconda3\Lib\site-packages\

# myenv
D:\miniconda3\envs\myenv\Lib\site-packages\

在 Linux 中则比较复杂,涉及到用户权限问题。如果 anaconda 是 root 用户安装的,base 环境属于 root 用户,普通用户创建自己的 myenv 环境,安装路径分别为

1
2
3
4
5
# base
/opt/anaconda3/lib/python3.11/site-packages

# myenv
~/.conda/envs/myenv/lib/python3.12/site-packages

pip + venv 和 conda 对比

对比一下这两种包和虚拟环境管理方案的优缺点:

  • pip + venv 的使用都比 conda 更加简单轻量;conda 环境还是太重了;
  • pip + venv 是 Python 官方支持的方案,使用更加自然,适合各种编程方向;Anaconda/Miniconda 是为科学计算设计的;
  • pip + venv 的使用可以严格限制在具体目录下,独立性很强,避免多个环境的干扰,对于复现环境的搭建更加方便,直接在项目目录下创建虚拟环境即可;conda 环境默认存放在全局的目录中,与项目的联系并不密切。
  • venv 只能基于当前系统安装的 Python 版本来创建虚拟环境,不能切换 Python 版本;conda 支持切换 Python 版本;
  • pip 只能管理 Python 包,但是 conda 可以管理其它包。