Python 包下载和虚拟环境管理
分成如下几个部分:
- 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
5site-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
按照惯例,虚拟环境的文件夹通常被设置为
.venv
或venv
。
这个命令会在当前目录下创建一组文件和子目录,通常包括以下几个关键部分:
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
5home = /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$
如果采用默认名称
.venv
或venv
,在 Windows 上的命令提示符可能会自动替换为显示当前文件夹名称。
使用 deactivate
命令可以退出当前的虚拟环境
1
deactivate
deactivate
可能是通过单独的 shell
脚本提供,也可能是通过定义的 shell 函数提供。
激活虚拟环境实际上就是调用了对应目录中的激活脚本,执行了一些简单操作,主要包括:
- 修改环境变量
PATH
,将当前目录添加到环境遍历路径的开头,确保python
,pip
等命令会优先找到当前虚拟环境中的实例; - 修改环境变量
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
3D:/miniconda3
D:/miniconda3/Scripts
D:/miniconda3/Library/bin
因为 Miniconda 可能含有各种包和软件,包括一些可执行文件,为了避免潜在的版本冲突(比如覆盖了其它在外部单独安装的软件),建议将这几个路径放在 PATH 靠后的位置。
Linux 安装 Miniconda:参考官网给出的安装过程即可
1
2
3
4mkdir -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
3wget 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
3conda 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
2conda 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
5auto_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
2conda install package_name
conda install package_name=1.2.3
更新包 1
conda update package_name
更新所有包(谨慎操作,这可能会破坏不同包之间的版本依赖关系)
1
conda update --all
非常有趣的是,conda update
和 conda upgrade
是完全一样的。
卸载包 1
conda remove package_name
使用 conda remove
和 conda 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
15name: 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
5powershell
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 可以管理其它包。