yield-bytes

沉淀、分享与无限进步

Python开发常用的虚拟环境管理配置

  在某些python的开发项目中,或跑一些demo,例如tensorflow的demo,要求python3.5以上的版本,若原系统环境只有python2.7.5,显然无法满足测试环境。若为系统安装python3.5+,有些库又会造成版本冲突,因此需要使用python的虚拟环境工具来解决这些矛盾。当然也可采用python的docker镜像,使用一个镜像独立环境运行项目,但相比于python虚拟化工具来说,这种docker镜像显得有点重。

1、python虚拟工具介绍

目前有几种方式创建python的虚拟环境,在python3中有标准库venv,而第三方库例如virtualenv、virtualenvwrapper、pyenv,那么在项目或者说在实际开发里面,选哪种工具更为适合?

1.1 virtualenv

virtualenv 是目前较为常用的 python 虚拟环境配置工具。它不仅同时支持 python2 和 python3,而且可以为每个虚拟环境指定 python 解释器(要求系统已经安装了不同版本的python),并选择不继承基础版本的site-packages。

1.2 virtualenvwrapper

virtualenvwrapper是virtualenv的一个封装,目的是使后者更好用。virtualenv在使用中,每次得去虚拟环境所在目录下的 bin 目录下 source activate,也即当有多个虚拟环境时,得每次都去找对应的目录,virtualenvwrapper将所有的虚拟环境目录全都集中起来统一管理,避免每次开启虚拟环境时候的source 项目目录操作。

1.3 venv

Python 从3.3 版本开始,自带了一个虚拟环境 venv,在 PEP-405 中可以看到它的详细介绍。它的很多操作都和 virtualenv 类似。也支持linux和win。venv也有局限性,例如当前系统python版本为3.5,那么venv只能在当前安装的python3.5版本,不能创建其它Python 3.x的版本以及Python 2的环境。

1.4 pyenv

pyenv主要用来安装、管理Python的版本及其虚拟环境,比如一个项目需要Python2.x,一个项目需要Python3.x。而virtualenv主要用来管理Python包的依赖。不同项目需要依赖的包版本不同,则需要使用虚拟环境。pyenv通过系统修改环境变量来实现Python不同版本的切换。前面的三个工具都是用于虚拟环境切换,pyenv是 Python 版本环境切换工具,将这两套工具结合使用,可以完美解决 python 多版本环境的问题。具体实例在第4节给出。

2、使用virtualenv创建和管理虚拟环境

2.1 为多个python版本安装相应的pip

centos7.5默认没有pip包,因此需求手动安装,本文系统已经安装python2.7和python3.6。这里给出python2.7的pip安装和python3.6的pip3安装。
pip安装依赖setuptools,首先为python2和python3安装相应setuptools

1
2
3
4
5
6
7
8
9
10
[root@localhost local]# pwd
/usr/local
[root@localhost local]# wget https://files.pythonhosted.org/packages/ab/41/ab6ae1937191de0c9cbc115d0e91e335f268aa1cd85524c86e5970fdb68a/setuptools-42.0.0.zip
[root@localhost local]# unzip setuptools-42.0.0.zip
[root@localhost local] cd setuptools-42.0.0
# 注意这里的python命令是连接到python2.7,所以setuptools库只在python2.7环境生效
[root@localhost setuptools-42.0.0]# python2.7 setup.py install

# 给python3.6安装setuptools
[root@localhost setuptools-42.0.0]# python3.6 setup.py install

这里为何使用python2.7或者python3.6,因为如果想要构建更多python版本,其shell执行命令例如python3.5,python3.7则会显得清晰而不混乱。

为python2和python3安装相应pip,跟setuptools安装流程一致。

1
2
3
4
5
6
7
8
9
10
11

[root@localhost local]# pwd
/usr/local
[root@localhost local] wget https://files.pythonhosted.org/packages/ce/ea/9b445176a65ae4ba22dce1d93e4b5fe182f953df71a145f557cffaffc1bf/pip-19.3.1.tar.gz
[root@localhost local]# unzip pip-19.3.1.tar.gz
[root@localhost local] cd pip-19.3.1
# 为python2.7 安装pip,最终命令执行路径在:/usr/local/bin/pip
[root@localhost pip-19.3.1] python2.7 setup.py install

# 为pytho3.6 安装pip,最终命令执行路径:/usr/local/bin/pip3
[root@localhost pip-19.3.1] python3.6 setup.py install
2.2 安装virtualenv

上面已经配置了python2.7环境和python3.6环境,virtualenv库无需在两种环境安装,这里安装到python2.7库下即可。

这里要注意:如果系统已经安装python3版本,且shell已经设定python命令是软链接到python3

1
2
[root@localhost opt]# ls -al /usr/bin/python
**** /usr/bin/python -> /usr/bin/python3

那么需要使用pip3安装 virtualenv,这样virtualenv库才会安装到python3的site-packages目录下,

如果shell已经设定python命令是软链接到python2

1
2
[root@localhost opt]# ls -al /usr/bin/python
**** /usr/bin/python -> /usr/bin/python2

那么需要使用pip安装 virtualenv,这样virtualenv库才会安装到python2的site-packages目录下。

若不按照上述的环境情况,安装virtualenv,会出现以下情况

1
2
3
4
5
[root@localhost opt]# virtualenv -v
Traceback (most recent call last):
File "/usr/bin/virtualenv", line 2, in <module>
import virtualenv
ModuleNotFoundError: No module named 'virtualenv'

当前python是软链到python3,而pip安装的virtualenv是在python2.7路径下,python3并没有virtualenv这个库

1
2
3
4
5
6
7
8
[root@localhost opt]# python3
Python 3.6.8 (default, Apr 25 2019, 21:02:35)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import virtualenv
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'virtualenv

virtualenv在python2.7路径下

1
2
3
4
5
[root@localhost opt]# python
Python 2.7.5 (default, Aug 7 2019, 00:51:29)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import virtualenv

解决办法:将当前python命令软链到python2

1
[root@localhost opt]# ln -s /usr/bin/python2 /usr/bin/python

2.3、virtualenv创建虚拟环境

在/opt/pvenv_test目录下,创建一个使用python2.7解释器、且独立安装第三方库的运行环境、名字为crmapp的python2.7项目环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost pvenv_test]# virtualenv  --python=python2.7    --no-site-packages  crmapp
Running virtualenv with interpreter /usr/bin/python2.7
Already using interpreter /usr/bin/python2.7
No LICENSE.txt / LICENSE found in source
New python executable in /opt/pvenv_test/crmapp/bin/python2.7
Also creating executable in /opt/pvenv_test/crmapp/bin/python
Installing setuptools, pip, wheel...

[root@localhost pvenv_test]# ls
crmapp
[root@localhost crmapp]# ls
bin include lib lib64
# 相关执行命令在bin目录下

# 激活当前环境
[root@localhost crmapp]# source bin/activate
(crmapp) [root@localhost crmapp]#

# 当前虚拟环境pip包没有引入系统的pip包,从而实现包不冲突
(crmapp) [root@localhost crmapp]# pip list
pip (9.0.1)
setuptools (28.8.0)
wheel (0.29.0)

在/opt/pvenv_test目录下,创建一个使用python3.6解释器、且独立安装第三方库的运行环境、名字为djwebsocket的python3.6项目环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost pvenv_test]# virtualenv  --python=python3.6    --no-site-packages  djwebsocket
Running virtualenv with interpreter /usr/bin/python3.6
Already using interpreter /usr/bin/python3.6
Using base prefix '/usr'
No LICENSE.txt / LICENSE found in source
New python executable in /opt/pvenv_test/djwebsocket/bin/python3.6
Also creating executable in /opt/pvenv_test/djwebsocket/bin/python
Installing setuptools, pip, wheel...
done.

[root@localhost pvenv_test]# source djwebsocket/bin/activate

# 可以看到当前pip包为干净的
(djwebsocket) [root@localhost pvenv_test]# pip list
Package Version
---------- -------
pip 19.3.1
setuptools 42.0.0
wheel 0.33.6

这里的 —python=python3 其实就是 /usr/bin/python3对于的python3.6解释器

3、pyenv终极python版本和虚拟化环境管理工具

有关virtualenvwrapper或者venv的用法,因内容较为简单,这里不再讨论,本文推荐使用pyenv管理任意基于python项目的虚拟环境。

3.1 pyenv的设计原理

pyenv主要用来管理Python的版本,比如一个项目需要Python2.x,一个项目需要Python3.x。而virtualenv主要用来管理Python包的依赖。不同项目需要依赖的包版本不同,则需要使用虚拟环境。

pyenv通过系统修改环境变量来实现Python不同版本的切换。而vitualenv通过Python包安装到一个目录来作为Python虚拟包环境,通过切换目录来实现不同包环境间的切换。

pyenv的设计巧妙的地方在于,在PATH 的最前面插入了一个垫片路径(shims):~/.pyenv/shims:/usr/local/bin:/usr/bin:/bin。所有对 Python 可执行文件的查找都会首先被这个 shims 路径截获,从而使后方的系统路径失效。

对于系统环境变量 PATH ,里面包含了一串由冒号分隔的路径,例如 /usr/local/bin:/usr/bin:/bin。每当在系统中执行一个命令时,例如 python 或 pip,操作系统就会在 PATH 的所有路径中从左至右依次寻找对应的命令。因为是依次寻找,因此排在左边的路径具有更高的优先级。在PATH 最前面插入一个 $(pyenv root)/shims目录,$(pyenv root)/shims目录里包含名称为python以及pip等可执行脚本文件;当用户执行python或pip命令时,根据查找优先级,系统会优先执行shims目录中的同名脚本。pyenv 正是通过这些脚本,来灵活地切换至我们所需的Python版本。

需要手工去查找python版本的所在路径,如果有多个版本,这种手工管理显得有点繁琐。

3.2 安装pyenv

pyenv安装python需要依赖底层的系统库

1
[root@localhost bin] yum install -y gcc make patch gdbm-devel openssl-devel sqlite-devel readline-devel zlib-devel bzip2-devel ncurses-devel libffi-devel

若系统库不全,pyenv安装python后,会有如下提示:

1
2
3
4
5
6
[root@localhost bin]# pyenv install 3.7.5
Installing Python-3.7.5...
WARNING: The Python bz2 extension was not compiled. Missing the bzip2 lib?
WARNING: The Python readline extension was not compiled. Missing the GNU readline lib?
WARNING: The Python sqlite3 extension was not compiled. Missing the SQLite3 lib?
Installed Python-3.7.5 to /root/.pyenv/versions/3.7.5

有三个warning提示,系统环境缺少 bzip2、readline、SQLite3。

下载pyenv

1
wget git clone https://github.com/pyenv/pyenv.git ~/.pyenv

PYENV_ROOTpyenv init加入bash的~/.bashrc(或zsh的~/.zshrc

1
2
3
echo 'export PATH=~/.pyenv/bin:$PATH' >> ~/.bashrc
echo 'export PYENV_ROOT=~/.pyenv' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

激活pyenv(zsh为~/.zshrc

1
source ~/.bashrc

指定python版本在线安装

1
[root@localhost bin]# pyenv install 3.7.5

常用命令

1
2
3
4
5
6
7
8
pyenv install --list # 列出可安装版本
pyenv install <version> # 安装对应版本
pyenv uninstall <version> # 卸载对应版本的python
pyenv uninstall <venv name> # 删除指定虚拟环境
pyenv install -v <version> # 安装对应版本,若发生错误,可以显示详细的错误信息
pyenv versions # 显示当前使用的python版本
pyenv which python # 显示当前python安装路径
pyenv global <version> # 设置默认Python版本

3.3pyenv离线安装python各版本

pyenv自动去官网拉取python安装包,如果要为离线服务器安装,则只需在.pyenv创建cache目录,将指定版本的python安装包放在该目录。

python安装包下载地址:https://www.python.org/ftp/python/

只需下载Python-*.tar.xz 即可

1
2
3
4
5
6
7
8
[root@localhost cache]# pwd
/root/.pyenv/cache
[root@localhost cache]# ls
Python-3.7.5.tar.xz

[root@localhost .pyenv]# pyenv install 3.7.5
Installing Python-3.7.5...
Installed Python-3.7.5 to /root/.pyenv/versions/3.7.5
3.4 使用多个python版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
pyenv设为系统原有python版本:
[root@localhost opt]# pyenv global system
[root@localhost opt]# python -V
Python 2.7.5

pyenv更换系统python3.7.5版本后:
[root@localhost opt]# pyenv global 3.7.5
[root@localhost opt]# python -V
Python 3.7.5
[root@localhost opt]# pyenv versions
system
* 3.7.5 (set by /root/.pyenv/version)

# python3.7.5所在目录,所有的安装python都会集中放置在.pyenv/versions目录下
[root@localhost bin]# pwd
/root/.pyenv/versions/3.7.5/bin
[root@localhost bin]# ls
2to3 idle pip3 pydoc3.7 python3.7-config python3-config
2to3-3.7 idle3 pip3.7 python python3.7-gdb.py python-config
easy_install idle3.7 pydoc python3 python3.7m pyvenv
easy_install-3.7 pip pydoc3 python3.7 python3.7m-config pyvenv-3.7

pyenv在python版本方面得心应手。

3.5 pyenv结合/pyenv-virtualenv实现灵活的虚拟环境管理

在第3.2章节介绍了virtualenv用于管理pip包的虚拟环境,virtualenv有个不足地方是:系统需已安装多个python版本,一般会通过手工安装,也即编译时指定不同路径,避免冲突。pyenv作者同时也开发pyenv-virtualenv的工具,跟virtualenv功能一致,也是用于管理pip包以及虚拟环境,结合pyenv,可以实现任意python版本以及pip包环境的切换以及使用,高效提高个人开发效率。

pyenv-virtualenv放在.pyenv/plugins 这个插件目录下

1
2
3
4
5
6
7
8
[root@localhost plugins]# pwd
/root/.pyenv/plugins
[root@localhost plugins]# git clone https://github.com/yyuu/pyenv-virtualenv.git
[root@localhost plugins]# ls
pyenv-virtualenv python-build

# 更新系统环境变量
[root@localhost plugins]# exec "$SHELL"

创建python3.7.5版本、虚拟环境名为tf375

1
2
3
4
5
6
7
8
9
10
11
[root@localhost opt]# pyenv virtualenv 3.7.5 tf375

# 所有使用python3.7.5版本创建的虚拟环境都在此目录:/root/.pyenv/versions/3.7.5/envs
[root@localhost envs]# ls
pyspark375 tf375

# tf375虚拟环境的目录在这里:
[root@localhost opt]# ls ~/.pyenv/versions/3.7.5/envs/tf375/
bin/ include/ lib/ lib64/ pyvenv.cfg

#pyenv uninstall tf375 # 删除虚拟环境,同时也会删除其目录

激活tf375环境,pyenv支持对环境名的自动补全,非常方便,pip包默认不继承系统包。

1
2
3
4
5
6
7
[root@localhost opt]# pyenv activate tf375 

(tf375) [root@localhost envs]# pip list
Package Version
---------- -------
pip 19.2.3
setuptools 41.2.0

创建python3.6.5版本、虚拟环境名为spk的pyspark开发环境

1
2
3
4
5
[root@localhost opt]# pyenv virtualenv 3.6.5 pyspark_proj
[root@localhost opt]# pyenv activate pyspark_proj
(pyspark_proj) [root@localhost opt]# pip list
pip (9.0.3)
setuptools (39.0.1)