Python 包下载和虚拟环境管理
包括两部分:
- pip:包下载安装
- venv:虚拟环境管理
在部分 Linux 发行版(例如 Ubuntu)中即使系统自带 Python,也可能只是包括了最基础的功能,并不包括 pip 和 venv,需要单独下载安装
1 | sudo apt-get install python3-pip python3-venv |
这些内容在不同的系统(Windows/Linux)中的实现细节各有不同,在不同的 shell(pwsh/bash/fish)中,对应的脚本实现也有差异,下面以 Linux + bash 为主,也会考虑 Windows + pwsh 的情况。
pip
基本使用
使用 pip 可以安装 Python 包,常见形式为
1 | pip install <package_name> |
例如安装进度条 tqdm
1 | pip install tqdm |
pip 会自动处理包的版本要求和依赖关系,依赖关系在不同系统下可能存在差异,例如:
- 在 Linux 上只会安装
tqdm自身; - 在 Windows 上会自动安装两个包:
colorama,tqdm,前者是tqdm的依赖。
但是 pip 在卸载时并不能自动处理这种依赖关系,而是采用了非常保守的策略:永远不会自动卸载依赖,例如卸载
tqdm不会导致它的依赖包colorama被卸载,用户必须手动操作。
卸载指定的包
1 | pip uninstall tdqm |
列出当前所有的包
1 | pip list |
升级指定的包
1 | pip install --upgrade requests |
可以在下载或升级时指定包的版本
1 | pip install requests==2.31.0 |
由于各个包之间可能存在复杂的依赖关系,批量安装和分别安装时会有不一样的结果:
- 批量安装:pip 会同时解析所有依赖,找到兼容的版本
- 分别安装:逐个安装,可能产生冲突或依赖覆盖
因此建议尽量一次性安装多个包,而不是逐个安装。
注意:
- pip 安装的包默认会存放在特定位置的
site-packages/目录(位置直接与当前 Python 解释器的位置有关,也就是与当前环境有关)。 - pip 本质上仍然是一个 Python 包,同名的可执行文件只是调用入口,实际会调用
site-packages/pip/目录中的内容。 - 在使用时
pip命令时要注意当前使用的是哪个环境(或虚拟环境)中的 pip。 - 由于 Python 本身是一个脚本语言,它的包管理器 pip 不仅可以提供用户需要的库,实际上也可以直接提供可执行文件,作为 apt/pacman 等系统包管理器的替代。
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 | [global] |
安装方式
除了通过 PyPi 进行安装之外,pip 还支持很多安装方式,下面分别介绍。
可以通过 Github 仓库安装:(包括 HTTPS 和 SSH)
1 | pip install git+https://github.com/user/repo.git |
当然这里要求该仓库的内容符合 Python 包的格式标准,例如有 setup.py 文件或者 pyproject.toml 等。
这里还可以指定 Git 仓库的分支或 tag
1 | pip install git+https://github.com/user/repo.git@main |
注意这里 pip 不会通过 commit 信息判断版本,而是基于 pip 包的版本号信息判断是否需要更新。
可以通过本地 Git 仓库安装:
1 | pip install path/to/local/repo |
可以通过 .tar.gz 或 .zip 文件进行源码安装:(也支持压缩包的 URL)
1 | pip install /path/to/package.tar.gz |
显然这里也要求压缩包中的内容符合 Python 包的格式标准)
此外,还可以使用 Python 的 wheel 文件(后缀 .whl)进行模块安装,wheel 文件是被设计替代源码压缩包的二进制文件,它相比于压缩包的优势是已经包含了所有编译好的二进制文件,因此安装速度更快,并且可以避免一些编译问题。
环境导出和恢复
我们可以使用 requirements.txt 记录当前环境(或虚拟环境)的第三方依赖,例如
1 | numpy |
在其中既可以指定版本,也可以忽略版本(不建议)。
pip 使用如下命令可以导出当前的所有依赖(包括具体的版本),并保存到文件中,方便下次在别的位置安装
1 | pip freeze > requirements.txt |
可以在其它位置通过该 requirements.txt 文件安装所有的依赖,从而恢复相同的环境(或虚拟环境)
1 | pip install -r requirements.txt |
venv
venv 是 Python 提供的一个模块,用于创建隔离的虚拟环境来管理不同项目的依赖关系,每一个虚拟环境存储于一个目录下,但是并不限于在这个目录下使用,实际可以在任何其它位置激活和使用这个虚拟环境。
创建虚拟环境
在当前目录下创建一个名为 myenv 的虚拟环境
1 | python -m venv myenv |
按照习惯,虚拟环境的文件夹通常被设置为
.venv或venv。(最好不要改动,否则还需要在 IDE 或者 shell 中进行额外的适配)
这个命令会在指定目录下创建一套 Python 运行时,通常包括以下几个关键部分:
bin/:包含一个虚拟的 Python 解释器(可执行文件)和 pip 以及命令脚本(针对各个shell);lib/pythonX.Y/site-packages/:存放该虚拟环境下所有的 Python 包,初始情况下可能只有 pip;include/:包含C语言头文件,用于在该虚拟环境中进行扩展编译。
注:
- 这里呈现的是 Linux 中的目录结构,对于 Windows 存在一些细微区别。在 Ubuntu 中设置了
lib64/ -> lib/。 - 虚拟环境是由当前使用的 Python 解释器创建的,虚拟环境中虽然有一个名为 Python 或 Python3 的解释器,但是实质上还在使用创建时对应的 Python 解释器。
- 虚拟环境不等于完整的 Python 运行时,只是改变了
site-packages以隔离第三方依赖,虚拟环境不能摆脱创建时使用的 Python 运行时而独立存在。
虚拟环境有一个关键的配置信息文件 pyvenv.cfg,其中记录了 Python 版本信息,创建时的命令等信息,大致内容形如:
1 | home = /home/xxx/miniconda3/bin |
在第一次创建虚拟环境之后,习惯上会在下载依赖之前更新一下 pip
1 | python -m pip install --upgrade pip |
venv 创建的虚拟环境会自带 pip,但是 uv 创建的虚拟环境就是不包含 pip 的。
激活、退出虚拟环境
虚拟环境所涉及的命令脚本实际上分别提供了 bash,cmd 和 pwsh 这几个版本,下面的讨论主要以 Linux 为例。
执行激活脚本可以激活(当前目录下的)虚拟环境,具体的激活命令与当前使用的 shell 相关,例如
1 | # windows pwsh |
说明:
- 在 Linux 中,不能直接执行对应脚本(因为这个脚本没有执行权限),而且只有通过
source(或.)启动后才会对当前进程有效;(在 Windows 中不存在这种问题) - 也可以激活和使用其它目录下的虚拟环境,只需要相应调整命令中的路径即可。
激活环境之后,shell 的命令行提示符通常会变化,自动提示当前虚拟环境的名称,通常是当前项目目录的名称,例如
1 | (myenv) user@xxx$ |
使用 deactivate 命令可以退出当前的虚拟环境
1 | deactivate |
deactivate 可能是通过单独的 shell 脚本提供,也可能是通过定义的 shell 函数提供。
激活虚拟环境实际上就是调用了对应目录中的激活脚本,执行了一些简单操作,主要包括:
- 修改环境变量
PATH,将当前目录添加到环境遍历路径的开头,确保python,pip等命令会优先找到当前虚拟环境中的 Python 解释器,这同时会把对应的site-packages/目录添加到模块搜索路径中,确保可以成功导入当前环境中所安装的包; - 修改环境变量
VIRTUAL_ENV记录当前的虚拟环境; - 修改当前 shell 的命令行提示符;(受到
VIRTUAL_ENV_DISABLE_PROMPT环境变量控制) - 提供一个
deactivate命令,作用就是将activate所做的修改撤销。
退出激活环境则是撤销了上述过程的影响。
如果要删除虚拟环境,直接删除虚拟环境对应的整个目录即可。
不建议把整个虚拟环境目录在文件系统中移动,venv 虚拟环境在移动后可能出现问题。
