Best Practice for Python Virtual Environment [Python虚拟环境的最佳实践]
个人认为的Python虚拟环境的最佳实践。
Python开发最大的一个问题就是版本兼容和环境隔离。Python的版本众多,还有数量庞大的第三方库,每个库可能还有众多版本,这时候如何确保在移植项目的时候正确安装python
和第三方库就十分重要了。比如,项目A和B需要不同的python版本,A只能运行在python2.7上,而B只能运行在python3.6上。又或者,A项目需要tensorflow 1.15,B项目则构建在tensorflow 2.1上。
针对这个问题,个人认为最好用的就是pyenv+virtualenv+pip
组合:
-
pyenv
用来管理不同版本的Python -
virtualenv
可以根据pyenv
提供Python,来创建独立的Python虚拟环境 -
进入
virtualenv
创建的虚拟环境之后,使用pip
安装需要的官方或第三方包,一般定义在requirements.txt
中
pyenv
pyenv可以安装并管理不同的python版本。
Installation
首先安装依赖库文件[https://github.com/pyenv/pyenv/wiki#suggested-build-environment]
sudo apt-get update
sudo apt-get install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncursesw5-dev \
xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
这里使用pyenv自带的installer安装[https://github.com/pyenv/pyenv-installer]
将pyenv安装到推荐位置~/.pyenv
,重启shell可以使安装生效。
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
# activate ~/.bashrc
source ~/.bashrc
Configuration
添加下列配置信息到~/.bashrc
,重启shell使安装生效。
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"
# activate ~/.bashrc
source ~/.bashrc
Update
pyenv
也需要定期更新才能显示最新的可以安装的python版本,通过下面的命令进行更新
pyenv update
Uninstallation
删除~/.pyenv
文件夹
rm -rf ~/.pyenv
从~/.bashrc
中删除下列配置信息
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv virtualenv-init -)"
# activate ~/.bashrc
source ~/.bashrc
Manage Python using pyenv
下面的命令可以显示所有可以安装的python版本
pyenv install --list
安装特定的python版本
pyenv install <PYTHON-VERSION>
# e.g., pyenv install 3.7.12
检查安装python版本,正常应该显示,system
和3.7.12
# 注意version和versions是不同命令
pyenv versions
可以通过下面命令卸载任何已经安装的python
pyenv uninstall <PYTHON-VERSION>
pyenv提供了global和local两个设定python的方式。
# global level
pyenv global <python-version>
# local level
pyenv local <python-version>
但是不推荐global的方式,毕竟可能涉及到系统python的设置。对于想用pyenv来管理不同的python版本,并且在创建virtualenv的时候指定对应的版本,那这里不用通过pyenv来设置global或者local,让pyenv保持system既可。
virtualenv
virtualenv应该是目前使用最广的python创建python虚拟环境的方式,它的特点在于安装使用简单,可以快速创建一个独立干净的python环境(无多与的pip安装包)。virtualenv对于创建不同环境用来部署不同版本的tensorflow和pytorch尤其有用。但是这个方法有一个问题,它创建的虚拟环境需要基于系统已经存在的python(如果安装了多个python版本,那么可以指定这些版本创建环境)。比如,如果系统安装了python3.8,那么创建的所有虚拟环境的解释器都是python3.8,这就意味着virtualenv无法创建一个基于python3.5的虚拟环境。
Installation
virtualenv是python主要的虚拟环境包。安装方式很简单
sudo apt install virtualenv
# or
# sudo pip3 install virtualenv
没有root权限进行pip3 install virtualenv
,会无法使用virtualenv
命令,因为带root权限会安装virtualenv到/usr/lib/pythonX.X/dist-packages
,而如果不带root权限会安装到~/.local/lib/pythonX.X/site-packages
Create virtualenv
安装后,就可以直接使用virtualenv
命令创建一个独立的干净Python运行环境。
virtualenv也可以是显式指定创建的虚拟环境使用哪个python版本(制定的版本必须已经预先安装,如果没有安装对应的python版本,virtualenv则无法创建)。
virtualenv <venv-name>
virtualenv -p python3 <venv-name>
virtualenv --python=/usr/bin/python3 <venv-name>
其实,上面三个命令效果相同,其实从后面两个命令可以看出,virtualenv需要找到python解释器,然后才能创建基于这个版本解释器的python虚拟环境。
Activate and deactivate virtualenv
默认使用的是用户和系统环境,激活后才是虚拟环境。
source venv/bin/activate
这时命令行前面会出现(<venv-name>)
,就证明进入了虚拟环境。使用pip3 list
会发现此环境只有初始化时候添加的pip, setuptools, wheel
。
通过deactivate
就可以退出虚拟环境
deactivate
pyenv + virtualenv + pip
配合pyenv
,我们就可以使用不同的python版本创建虚拟环境。
# 指定python的路径为pyenv安装的位置,比如:
virtualenv --python=/home/{user_name}/.pyenv/versions/3.7.9/bin/python3 <venv-name>
可以通过pip3 install -U setuptools
和pip3 install -U pip
来更新创建的虚拟环境中的pip
和setuptools
在此虚拟环境中,可以通过pip
来安装需要的包。
同时,我们可以通过源码编译安装某一Python版本,并指定virtualenv使用对应的地址创建虚拟环境
Misc
venv
从Python 3.3开始,标准库中就自带了一个venv模块,拥有virtualenv的部分功能。因此,也可以通过以下命令来创建虚拟环境。
python3 -m venv venv-name
当然了因为只有部分功能,所以还是推荐使用virtualenv。比如,venv只能根据当前python解释器来创建虚拟环境。
pipenv
pipenv
是 Python 官方推荐的包管理工具,它综合了virtualenv
,pyenv
,pip
三者的功能,它的目标是将所有包管理领域[bundler, composer, npm, cargo, yarn 等]的最好体验带到python世界中来 (Pipenv is a tool that aims to bring the best of all packaging worlds (bundler, composer, npm, cargo, yarn, etc.) to the Python world.)。
pipenv
可以通过简单的命令创建一个python
虚拟环境,这是并不需要像virtualenv
一样[当然也可以做到],通过source
命令进入虚拟环境,而是可以通过pipenv run ...
命令在对应的虚拟环境中执行操作,比如pipenv run pip3 install torch torchvision torchaudio
会在创建的虚拟环境中安装 pytorch。pipenv
的更多命令和具体使用说明可以在其官网找到,不再赘述。简单来说,就是用pipenv
一个命令实现pyenv+virtualenv+pip
的功能。
requirements.txt vs pipfile
其实在一些场景下requirements
方式就可以满足需求,但是在复杂场景下这种方式就力不从心了:
-
requirements.txt
文件中只记录了依赖的版本,所以如果遇到官方的 pypi 源下载速度慢,需要使用其他的镜像下载,通常只能使用pip install -i
安装或者修改全局的pip.conf
文件。这对于自动部署都是不友好的。 -
当某个项目使用确定的
python
版本,python
版本不能在requirements.txt
中体现,只能通过 readme 或者文档来记录,并且需要在创建虚拟环境时手动使用正确的python
版本。 -
开发环境和生产环境需要的依赖库可能是不一样,但是
requirements.txt
无法体现出这些出别,例如,项目需要使用flake8
,pylint
,black
等代码优化工具时,这些依赖也会被pip freeze
命令写入requirements.txt
中,然而这些依赖是不需要出现在生产环境的。
pipenv
和pipfile
的出现可以解决上出问题,pipfile
允许设置pip
源,并且支持默认环境和开发环境不同的依赖。
例如下面的例子pipfile
,[[source]]
定义了pip
源,[dev-packages]
定义了开发环境下的依赖,[packages]
定义了默认环境下的依赖,[requires]
则确定了python
的具体版本。
[[source]]
name = "pypi"
url = "https://xxx.xxxxx.xxx/simple"
verify_ssl = false
[dev-packages]
black = "==19.3b0"
pylint = "*"
[packages]
flask = "*"
pandas = "*"
requests = "*"
openpyxl = "*"
[requires]
python_version = "3.6"
同时,pipenv
可以自动生成Pipfile.lock
文件,中记录了当前环境中安装的依赖的版本号以及哈希,以保证每次根据这些值安装的依赖都是一致的,该文件用来保证包的完整性。任何情况下不要手动修改该文件。