Python conda 使用笔记
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 | mkdir -p ~/miniconda3 |
Linux 安装 Anaconda
1 | wget https://repo.anaconda.com/archive/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 | D:/miniconda3 |
这样做的效果是 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 | # >>> 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 | # -*- coding: utf-8 -*- |
激活、退出 conda 环境
注意使用 venv 创建的虚拟环境和 conda 创建的 conda 环境并不一样。
conda 激活指定的 conda 环境(缺省环境名时会自动激活 base 环境)
1 | conda activate |
退出 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 | # base |
可以通过查询当前 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 | conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/ |
这两个配置实际会存储在用户家目录下的配置文件 ~/.condarc 中,内容如下
1 | auto_activate_base: false |
conda 包管理
在当前 conda 环境中列出已安装的包(与 pip list 的内容并不完全一样)
1 | conda list |
在 conda 仓库中查找包
1 | conda search package_name |
安装包(可以指定包的版本)
1 | conda install package_name |
一次性安装多个包比逐个安装包更好,因为这会让 conda 更容易处理版本依赖关系。
更新包
1 | conda update package_name |
更新所有包(谨慎操作,这可能会破坏不同包之间的版本依赖关系)
1 | conda update --all |
卸载包
1 | conda remove package_name |
有趣的是,conda update 和 conda upgrade 是完全一样的,conda remove 和 conda uninstall 是完全一样的。
清理当前环境所有的缓存文件和索引数据
1 | conda clean --all |
conda 环境导出和恢复
下面提供两种 conda 环境迁移的方法。
第一种方法,使用如下命令导出包列表
1 | conda list --explicit > spec-list.txt |
其中的内容大致为
1 | # This file may be used to create an environment using: |
然后在别的位置可以通过 spec-list.txt 文件创建 conda 环境
1 | conda create --name newenv --file spec-list.txt |
第二种方法,使用如下命令导出 conda 环境信息
1 | conda env export > environment.yml |
其中的内容大致为
1 | name: base |
然后在别的位置可以通过 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 | D:\ProgramLang\miniconda3 |
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 | powershell |
在完成 conda init 配置,并设置 conda 不自动激活环境时,登陆 shell 时的默认情况通常为
1 | # Windows(powershell) |
这里 Windows(powershell) 和 Linux(bash) 的表现略有不同。手动激活环境(或者设置自动激活环境),相关的环境变量就会变为
1 | # Windows(powershell) |
conda init 的 powershell 启动优化
在 Windows 的 Powrshell 中,conda init 命令会自动在 Powershell 的配置文件 profile.ps1 中添加以下内容:
1 | #region conda initialize |
这段命令非常影响启动速度,即使不激活 base 环境,还是有 1s 左右的耗时,因此考虑优化一下。
解读一下这段命令可知,本质就是获取一个字符串然后在pwsh中执行,这个字符串的内容在固定的平台上也是固定的,所以我们可以直接手动执行一次以获取结果
1 | (& "/path/to/conda.exe" "shell.powershell" "hook") | Out-String |
然后将输出的内容硬编码到 profile.ps1 中,输出内容形如
1 | $Env:CONDA_EXE = "/path/to/conda.exe" |
可能还有conda activate base,将其删掉,不用激活环境。
注:powershell 在文档路径下有很多名称相似的启动脚本,涉及到各种权限细节,需要注意一下
WindowsPowershell/profile.ps1:这是旧版 windows powershell 的启动脚本,无需考虑;Powershell/profile.ps1:这是新版 pwsh 的启动脚本;Powershell/Microsoft.PowerShell_profile.ps1:这也是新版 pwsh 的启动脚本,而是还是$PROFILE的值。
conda init 命令会在前两个 profile.ps1 都添加启动命令片段,通常建议用户对 pwsh 的启动配置写在第三个脚本中,
按照官网的说法,它代表 CurrentUserCurrentHost,而第二个脚本代表 CurrentUserAllHosts。pwsh 在启动时会先加载第二个脚本,然后加载第三个脚本。
习惯上新版 powershell 不会加上前缀 windows,用于和旧版区分,有时还会使用缩写 pwsh。
