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

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

事实上,Anaconda 和 Miniconda 之间还可能存在一些差别,并且不同版本之间,在不同的系统上的行为都可能存在差异。

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

1
conda install numpy scipy matplotlib sympy jupyter tqdm

Anaconda 公司对 defaults 仓库的商用行为存在限制,开源社区提供的替代品为 miniforge,与 miniconda 的主要区别是修改了默认的 channel 为开源社区的 anaconda.org,此外还额外提供了 mamba 可以替代 conda。

安装 Anaconda/Miniconda

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

下面简单描述 Linux/Windows 安装 Miniconda/Anaconda 的过程,值得注意的是:

  • Linux 系统通常有系统自带的 Python 环境,而 Windows 并没有;
  • Linux 系统需要严格区分 root 和普通用户的操作,而 Windows 对此并不严格。

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

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

卸载只需要对上述操作反向进行即可,包括:

  • 删除主目录,例如 ~/miniconda3
  • 删除 shell 初始化配置,例如 ~/.bashrc 的代码段
  • 删除相关数据目录,包括 ~/.conda/~/.cache/conda*

如果是 root 用户进行全局安装,将安装目录修改为/opt/anaconda3即可。

官方网站显示,它其实提供了卸载脚本 uninstall.sh,直接执行即可。

root 用户需要考虑安装目录的权限,最好不允许其它用户写入,这样可以保证 base 环境的安全性:其它用户即使在 base 环境安装新的包,也只能 fallback 安装到自己的本地路径上(默认是 ~/.local/ 的路径),不会影响其它用户。

Windows 安装 Miniconda:直接下载安装程序执行即可,注意修改一下安装位置和 PATH 的处理。

安装程序可能会提示是否修改 PATH 环境变量,可以直接确定,也可以稍后手动进行,此时需要将一些路径手动到 PATH 中,有两种选择,对应两种使用方式:

第一种选择是把下面几个路径全部加上去

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

这样做的效果是 base 环境“隐式全局化”:不需要激活 conda 环境也可以直接用 Python,也就是 conda base 环境提供的 Python。

与 Linux 不同,Windows 本身并没有全局自带的 Python 环境,因此可以直接将 conda base 环境作为全局默认的 Python 环境。由于 Miniconda 可能还含有各种包和软件,包括一些可执行文件,为了避免潜在的版本冲突(比如覆盖在外部单独安装的其它软件),建议将这几个路径放在 PATH 靠后的位置。

第二种选择是只添加 condabin 对应的路径

1
D:/miniconda3/condabin

这样做的效果是:默认 conda 环境的 Python 是不可用的,只有手动激活后,conda 才会把对应环境的路径加到 PATH 中。(这适合对 Python 环境进行精细管理的用户)

conda init

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

1
conda init

这个命令的核心作用是使当前 shell 支持 conda activate 和 conda deactivate 等基础操作。

这个操作实际会自动在 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 环境。默认情况下,会在进入 shell 时自动激活 base 环境,此时在命令行提示符中通常会显示 (base),这代表已经进入了默认的 base 环境。

  • conda init 在 Linux 平台默认对 bash 进行配置,在 Windows 平台默认对 pwsh 进行配置,注意默认行为并不是对当前 shell,因此对于 Linux 平台的 fish,不可以省略参数:conda init fish

  • 如果是 root 用户在 Linux 平台进行的全局安装,可以选择让每个用户手动配置,也可以进行全局的启动配置,对应脚本通常为 /etc/profile.d/conda.sh

conda 命令实际在 Linux 中只是个入口脚本(在Windows上会略有不同,但是仍然也只是脚本),内容很简单

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding: utf-8 -*-
import sys
# Before any more imports, leave cwd out of sys.path for internal 'conda shell.*' commands.
# see https://github.com/conda/conda/issues/6549
if len(sys.argv) > 1 and sys.argv[1].startswith('shell.') and sys.path and sys.path[0] == '':
# The standard first entry in sys.path is an empty string,
# and os.path.abspath('') expands to os.getcwd().
del sys.path[0]

if __name__ == '__main__':
from conda.cli import main
sys.exit(main())

激活、退出 conda 环境

注意使用 venv 创建的虚拟环境和 conda 创建的 conda 环境并不一样。

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

1
2
3
conda activate

conda activate myenv

退出 conda 环境

1
conda deactivate

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

为了避免 anaconda 和 miniconda 的一些可执行文件造成的影响,在不激活的状态下,只需要把 condabin 这个子目录加到 PATH 即可,
此时,在激活某个 conda 环境时,就会自动把此环境中 Python 解释器所在的路径(例如 /opt/anaconda3/bin)也添加到 PATH 中,而且为了保证优先级,通常是添加到 PATH 的头部。

如果在未激活 conda 环境时已经把 base 环境的路径(例如 /opt/anaconda3/bin)添加到 PATH,会导致 base 环境“隐式全局化”:即使看起来没有激活 base 环境,但是实际上已经在使用 base 环境的 Python 和其它可执行文件。

除了修改 PATH,在 Linux 中,conda 还会做一些其他事情,例如为了解决 Linux glibc 版本过低的问题,conda 会修改 glibc 的链接路径,将其替换为 conda 提供的 glibc,从而使得程序可以正常运行。

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

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

conda 环境管理

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

  • 创建一个全空的 conda 环境(不推荐)
1
conda create --name myenv1
  • 创建一个新的 conda 环境,指定 Python 版本
1
conda create --name myenv2 python=3.12.1
  • 克隆已有的 conda 环境来创建新的 conda 环境
1
conda create --name myenv3 --clone myenv

注意:

  • 在创建新的 conda 环境时最好指定 Python 版本,全空的环境甚至不包括 Python 和 pip 等基础包,可能导致错误使用;
  • 支持指定 Python 版本是 conda 环境相比于 venv 虚拟环境的一大优势,后者无法改变 Python 版本。
  • 不要尝试升级或降级环境中的 Python 版本,因为所有的包都依赖于固定的 Python 的版本号,这几乎会毁掉整个环境,对于切换 Python 版本的需求应该直接新建一个 conda 环境并指定 Python 版本;

列出当前的所有 conda 环境

1
conda env list

查看当前 conda 环境的信息

1
conda info

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

1
conda remove --name myenv --all

与 venv 虚拟环境的局部化思路不同,conda 环境是全局化的,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/

可以通过查询当前 Python 的位置来查找对应的 conda 环境路径

1
which python

conda 配置

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

1
conda config --show

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

1
conda config --set auto_activate False

对于旧版本,需要把 auto_activate 改成 auto_activate_base

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

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

conda 包管理

在当前 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

一次性安装多个包比逐个安装包更好,因为这会让 conda 更容易处理版本依赖关系。

更新包

1
conda update package_name

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

1
conda update --all

卸载包

1
conda remove package_name

有趣的是,conda updateconda upgrade 是完全一样的,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 文件创建 conda 环境

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

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

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 文件创建 conda 环境

1
conda env create -f environment.yml

两种方式的区别:

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

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

这里导出的包通常很多,但是绝大多数我们都不需要,我们实际只关注那些通过命令手动安装的包,conda 支持这样的操作,可以基于 conda 的日志导出必要的包

1
conda env export --from-history > env_minimal.yml

conda 对比 pip + venv

关于 conda 和 pip 混用:

  • 对于 Python 来说,conda 可以安装的包的数量还是远没有 pip 那么丰富,有的库(例如最新版的 PyTorch)甚至不提供 conda 包,只提供 pip 包,此时我们就面临着在 conda 环境中混合使用 conda 和 pip 的问题。
  • conda 和 pip 自身都会尝试解决各个包之间的版本要求和依赖关系等,conda 的依赖管理比 pip 更强大,显然混用 conda 和 pip 时更容易产生额外的风险。
  • conda 环境中通常都自带单独的 pip,使用 conda 环境中的 pip 安装的包就可以在这个 conda 环境中使用,因此需要注意必须在激活 conda 环境后使用这个环境中的 pip,而不要误用 Linux 系统的 pip 或者 base 环境的 pip,不确定时可以使用 which pip 检查。

对比一下 pip + venv 和 conda 这两种包和虚拟环境管理方案:

  • pip + venv 是 Python 官方支持的方案,使用更加自然,适合各种编程方向;Anaconda/Miniconda 是为科学计算设计的。
  • 在处理依赖关系时,pip 的处理非常简单保守:下载时递归获取依赖,卸载则不处理依赖;conda 会解析依赖关系,但是卸载时仍然不会自动卸载依赖,不过提供了相应的选项清理不需要的依赖。
  • pip + venv 的使用可以严格限制在具体项目中,虚拟环境非常轻量级,并且独立性很强;conda 环境相对较重,默认存放在全局的目录中,与项目之间的联系并不密切。
  • venv 不能切换 Python 版本;conda 支持切换 Python 版本。
  • pip 只能管理 Python 包,但是 conda 可以管理其它包。
  • conda 提供了完整的操作记录,包括包的版本变化历史,但是 pip 缺少此功能。

补充

关于 Windows 的环境变量

这里需要补充说明一下 Windows 的环境变量,环境变量不区分大小写。
Windows 提供了系统级和用户级环境变量,其中最重要的是 PATH

如果我们在用户级环境变量和系统级环境变量中创建除了 PATH 以外的同名变量,那么 Windows 会将用户级变量覆盖系统级变量。
但是 windows 对于 PATH 变量的处理方式很特别:将用户级 PATH 添加到系统级 PATH 后面,呈现的效果是系统级 PATH 的优先级反而更高。

在默认情况下,Windows 的用户级 PATH 中有一个特别的路径

1
C:\Users\<用户名>\AppData\Local\Microsoft\WindowsApps

这个路径下存放了很多只有 0kb,起到特殊占位作用的 exe 文件,例如 python.exe,点击会跳转到微软应用商店的 Python 下载页面。
因此,为了保证 python 的正常使用,在向环境变量中添加 anaconda3/miniconda3 的相关路径时,必须保证路径排序在它之前。

1
2
3
D:\ProgramLang\miniconda3
D:\ProgramLang\miniconda3\Scripts
D:\ProgramLang\miniconda3\Library\bin

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_SHLVL 的值)

这些变量都是由 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 init 的 powershell 启动优化

在 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,将其删掉,不用激活环境。

注:powershell 在文档路径下有很多名称相似的启动脚本,涉及到各种权限细节,需要注意一下

  1. WindowsPowershell/profile.ps1:这是旧版 windows powershell 的启动脚本,无需考虑;
  2. Powershell/profile.ps1:这是新版 pwsh 的启动脚本;
  3. Powershell/Microsoft.PowerShell_profile.ps1:这也是新版 pwsh 的启动脚本,而是还是 $PROFILE 的值。

conda init 命令会在前两个 profile.ps1 都添加启动命令片段,通常建议用户对 pwsh 的启动配置写在第三个脚本中,
按照官网的说法,它代表 CurrentUserCurrentHost,而第二个脚本代表 CurrentUserAllHosts。pwsh 在启动时会先加载第二个脚本,然后加载第三个脚本。

习惯上新版 powershell 不会加上前缀 windows,用于和旧版区分,有时还会使用缩写 pwsh。