车海快讯

Python | 虚拟环境

admin 105
前言

通常,在不同的项目中,会用到不同的Python版本——如果有必要的话,也包括一些库的版本,并非总是最新的就是最适合的或者最好的。对此,解决之道就是创建虚拟环境。

一个项目创建一个虚拟环境,在每个虚拟环境之中,就相当于一个“裸机”,里面所需要的东西任你根据当前的需要自由配置,并且不会影响到其他项目。特别是在诸如Linux系统上,有时候安装某些东西还需要root权限,此时虚拟环境的好处就更明显了。

创建虚拟环境

不论是Python2,还是Python3中,都可以创建虚拟环境——虽然现在广泛使用Python3,但也有项目在Python2上跑着呢。只是两个版本中创建方法稍有区别。

在Python3中创建虚拟环境

下面的方法是Python3中推荐的方法,务必掌握。

$python3-mvenvpython3venv

命令行上的-m参数是告诉解释器运行venv模块,此模块是Python3核心发行版的一部分。python3venv是虚拟环境的目录名称。执行之后就会创建python3venv,虚拟环境就在这个目录中。

如果对venv好奇,可以用下面的方式来瞧一瞧。

$(:d48ecebad5,Dec182017,21:07:28)[()(dot3)]ondarwinType"help","copyright","credits"or"license"(venv)module'venv'from'/Library/Frameworks//Versions/3.6/lib//venv/__init__.py'

venv模块的代码在/Library/Frameworks//Versions/3.6/lib//venv/__init__.py,查看此文件(执行cat/Library/Frameworks//Versions/3.8/lib//venv/__init__.py即可看到),并到最底部,会看到如下内容:

if__name__=='__main__':rc=1try:main()rc=0exceptExceptionase:print('Error:%s'%e,file=)(rc)

如果要查看命令行的参数,可以:

$python3-mvenvusage:venv[-h][--system-site-packages][--symlinks|--copies][--clear][--upgrade][--without-pip][--promptPROMPT]ENV_DIR[ENV_DIR]venv:error:thefollowingargumentsarerequired:ENV_DIR
在及更低版本中创建虚拟环境

现在不推荐这种方法,但是,也介绍一下。因为这个方法主要用于及以下版本中。

及以下版本有一个名为pyvenv的可执行文件,它本质上是venv模块的二进制包装器。如果按按照下面的方法操作,就可以看到命令行的参数。

$pyvenvWARNING:thepyenvscriptisdeprecatedinfavourof``usage:venv[-h][--system-site-packages][--symlinks|--copies][--clear][--upgrade][--without-pip][--promptPROMPT]ENV_DIR[ENV_DIR]venv:error:thefollowingargumentsarerequired:ENV_DIR

使用它创建虚拟目录的方法是:

$pyvenvpython3venvWARNING:thepyenvscriptisdeprecatedinfavourof``

但是,会告诉我们,这个东西弃用了,后面要使用前面推荐的方法。

在中创建虚拟环境

在上,用virtualenv模块创建虚拟环境。在不同的操作系统中,对virtualenv可能有不同的处理方式,比如有的默认就安装了这个模块,有的没有安装,这就需要你先安装上。

检查一下它是不是在你的机器上了。

$whichvirtualenv/Library/Frameworks//Versions/2.7/bin/virtualenv

创建一个的虚拟目录,其语法类似于前面的方法:

$virtualenvpython2venvNewpythonexecutablein/Users/james/python2venv/bin/pythonInstallingsetuptools,pip,wheeldone.
检查虚拟环境

已经创建了两个虚拟环境的目录,分别是:

$lspython3venvpython2venv/python2venv/:binincludelibpython3venv:

这两个目录的却别在于,python3venv中能够看到文件,如果你有兴趣了解有关此文件的更多信息,可以在PEP-0405查看相关的背景知识。

激活虚拟环境

要使用虚拟环境,必须先激活。

注意,虚拟环境激活前后,shell的提示符会发生变化。原来是这样的:

$echo$PATH/Library/Frameworks//Versions/3.6/bin:/Library/Frameworks//Versions/2.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

激活虚拟环境之后(执行sourcepython3venv/bin/activate指令后)显示(python3venv)$。

$sourcepython3venv/bin/activate(python3venv)$

检查路径后,虚拟环境将优先于前面做同样操作是呈现的路径。

(python3venv)$echo$PATH/Users/james/python3venv/bin:/Library/Frameworks//Versions/3.6/bin:/Library/Frameworks//Versions/2.7/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
执行python

如果我们现在执行python或pip,由于路径优先(前面的操作已经显示,优先执行了虚拟环境中),来自虚拟环境命令将优先执行。如果用下面的方式查看,会发现它们都在相应的虚拟环境中。

(python3venv)$whichpython/Users/james/python3venv/bin/python(python3venv)$whichpip/Users/james/python3venv/bin/pip

比如执行python,本来本地机器上安装两个版本的Python,如果不用虚拟环境,python之后默认会执行Python2,要执行Python3,必须是python3。但是,现在不同了,因为激活了的虚拟环境,当执行python命令后,会首先在指定的虚拟环境中搜索。并且,进入到Python3之后,查看,当前虚拟环境目录也被添加到Python搜索路径中了。

(python3venv)$(:d48ecebad5,Dec182017,21:07:28)[()(dot3)]ondarwinType"help","copyright","credits"or"license"()['','/Library/Frameworks//Versions/3.6/lib/','/Library/Frameworks//Versions/3.6/lib/','/Library/Frameworks//Versions/3.6/lib//lib-dynload','/Users/james/python3venv/lib//site-packages']
用pip安装软件包

激活虚拟环境后,使用pip会将模块或者第三方包直接安装到虚拟环境。例如,如果我们安装了名为arrow的模块——专门解读日期、时间的模块,比传统的datatime模块使用更方便。

(python3venv)$pipinstallarrowCollectingarrowDownloading(fromarrow)Downloading(226kB)100%|████████████████████████████████|235/sCollectingsix=1.5(frompython-dateutil-arrow)Downloading'pipinstall--upgradepip'command.

上面的安装过程显示,在安装了arrow的过程中,还安装了six和python-dateutil两个依赖模块。我们可以再次确认arrow模块在虚拟环境中。

(python3venv)$(:d48ecebad5,Dec182017,21:07:28)[()(dot3)]ondarwinType"help","copyright","credits"or"license"(arrow)module'arrow'from'/Users/james/python3venv/lib//site-packages/arrow/__init__.py'
升级pip

在上面用pip安装的时候,最后有警公告,提示要升级pip,如果看到这个提示,就要必须升级,为什么?请阅读:

必须升级pip,为什么?!

可以按以下方式升级虚拟环境中的pip。

(python3venv)$pipinstall--upgradepipCacheentrydeserializationfailed,entryignoredCollectingpipUsingcached(python3venv)$/Users/james/python3venv/lib//site-packages/pip()
集成环境需求

为了让下面的示例更能说明问题,在安装flask——一个用于web开发的框架。

(python3venv)$pipinstallflaskCollectingflaskDownloading(91kB)100%|████████████████████████████████|92/sCollectingJinja2=2.10(fromflask)Downloading(126kB)100%|████████████████████████████████|133/sCollectingWerkzeug=0.14(fromflask)Downloading(322kB)100%|████████████████████████████████|327/sCollectingitsdangerous=0.24(fromflask)Downloading;=5.1(fromflask)Downloading(81kB)100%|████████████████████████████████|81/sCollectingMarkupSafe=0.23(fromJinja2=2.10-flask)Downloading

安装flask的同时,也会安装相关的依赖模块。这样,在虚拟环境中就有了比较多的模块,而且每个模块(或者库)都有一定的版本。

下面按照如下的指令执行,目的是要生成一个名为的文件,在这个文件中,将记录当前虚拟环境中所安装的模块及其版本(注意,文件目录,先下面代码这样指定,是为了后面使用方便。)。

(python3venv)$pipfreeze|tee/tmp/==0.13.1Click==7.0Flask==1.0.2itsdangerous==1.1.0Jinja2==2.10MarkupSafe==1.1.1python-dateutil==2.8.0six==1.12.0Werkzeug==0.14.1

有了这个文件,当我们需要重现这个虚拟环境中已经安装的各个模块是,就简单了。

重现虚拟环境配置

前面,曾经创建了一个Python2的虚拟环境,现在要将刚才在Python3的虚拟环境中安装的各个模块(即配置),移植到Python2的虚拟环境中——注意,这种做法并不提倡,但是,这里纯粹是为演示虚拟环境的重现移植。

首先,将现在的python3venv虚拟环境停用。

(python3venv)$deactivate$

然后激活Python2的虚拟环境python2venv。

$sourcepython2venv/bin/activate(python2venv)$

升级pip,多数情况下,用pipinstall–upgradepip即可,但是,如果遇到了意想不到的事情,可以用下面的方式尝试解决。

$(python2venv)curl|python%Total%Received%XferdAverageSpeedTimeTimeTimeCurrentDloadUploadTotalSpentLeftSpeed1001659k1001659k002375k0--:--:----:--:----:--:--2377kDEPRECATION:,2020.'

现在,要将python3venv中的配置,在当前虚拟环境中重现,方法如下:

$(python2venv)pipinstall-r/tmp/:,2020.'==0.13.1(from-r/tmp/(line1))Usingcached(from-r/tmp/(line2))Usingcached(from-r/tmp/(line3))Usingcached(from-r/tmp/(line4))Usingcached(from-r/tmp/(line5))Usingcached(from-r/tmp/(line6))Downloading(from-r/tmp/(line7))Usingcached(from-r/tmp/(line8))Usingcached(from-r/tmp/(line9))Usingcached;=1.2.1;python_version=="2.7"(fromarrow==0.13.1--r/tmp/(line1))Downloading

虽然现在是一个Python2的虚拟环境,但是也按照文件中的记录,配置了与Python3虚拟环境相同的各个模块,并且还根据Python2的特定要求,增加了应有的依赖==1.5。于是当前虚拟环境中的配置如下:

(python2venv)$pipfreezeDEPRECATION:,2020.'==0.13.1==1.5Click==7.0Flask==1.0.2itsdangerous==1.1.0Jinja2==2.10MarkupSafe==1.1.1python-dateutil==2.8.0six==1.12.0Werkzeug==0.14.1
不激活的情况下,使用虚拟环境

一般情况下,按照上面所说的,激活虚拟环境,然后开始使用,这已经很方便了。但是,在某些情况下,或许有不激活虚拟环境的需求。

为此,可以这么做。比如要执行虚拟环境python3venv中的Python3,可以在没有激活任何虚拟环境的情况下,直接执行python3venv/bin/python运行python3venv中的Python。

在下面的操作中,首先要从python2venv的虚拟环境中退出。

(python2venv)$deactivate$python3venv/bin/(:d48ecebad5,Dec182017,21:07:28)[()(dot3)]ondarwinType"help","copyright","credits"or"license"(arrow)module'arrow'from'/Users/james/python3venv/lib//site-packages/arrow/__init__.py'^D$python2venv/bin/(:84471935ed,Sep162017,12:01:12)[()(dot3)]ondarwinType"help","copyright","credits"or"license"(arrow)module'arrow'from'/Users/james/python2venv/lib//site-packages/arrow/__init__.pyc'^D

在程序文件中,也可以指定所使用的虚拟环境,方法就是用!/Users/james/python3venv/bin/pythonimportarrowutc=()print(utc)EOF

设置示例文件可执行,然后执行,可以确认执行了虚拟环境中的模块.

$chmodu+$./:17:22.632130+00:00

如此,即可根据特定需求执行程序了。

打包

如果在本地完成了开发,要将程序移植到别的机器上,通常要在目标机器上配置与本地一样的环境。当然,现在有一种容器化的方案,比如使用docker等。如果不那样做,按照上面的方法完成了虚拟环境的配置,并且在虚拟环境中完成了程序编写。那么,就可以将真个虚拟环境打包。当然,这里有一个前提,目标机器上必须安装了与虚拟环境中相同版本的Python。

以前面使用过的python3venv为例,用tar命令将目录python3venv打包。

$

为了演示需要,将当前的python3venv目录删除。

$rm-rfpython3venv

然后从中将目录提取出来。

$

继续使用测试一下,python3venv虚拟目录及其内部安装的各模块,都已经恢复。

$./:26:47.082092+00:00
用pip管理虚拟环境

pip是一个好工具,它为管理和维护虚拟环境及其依赖提供简便方法。比如,对于虚拟环境python3venv中的模块,如果要删除arrow和flask,如下操作所示,使用pipuninstallpackagename即可,不过,安装时候所安装的那些依赖项会依然保留.

(python3venv)$:Wouldremove:/Users/james/python3venv/lib//site-packages//*/Users/james/python3venv/lib//site-packages/arrow/*Proceed(y/n)?:Wouldremove:/Users/james/python3venv/bin/flask/Users/james/python3venv/lib//site-packages//*/Users/james/python3venv/lib//site-packages/flask/*Proceed(y/n)?(python3venv)$pipfreezeClick==7.0itsdangerous==1.1.0Jinja2==2.10MarkupSafe==1.1.1python-dateutil==2.8.0six==1.12.0Werkzeug==0.14.1

除了上面简单的方法之外,还可以通过pip-tools中的工具,实现对模块更灵活的管理。

首先,要退出当前的虚拟环境,并删除python3venv目录。然后,重新创建虚拟环境——从这就可以看出虚拟环境的优势,你可以任意删除和重建,每次重建之后它都是“干干净净”的。

进入到新建的虚拟环境之后,升级pip——这是常规套路。再安装pip-tools。

(python3venv)$deactivate$rm-rfpython3venv$python3-mvenvpython3venv$sourcepython3venv/bin/activate(python3venv)$pipinstall--upgradepipCacheentrydeserializationfailed,entryignoredCollectingpipUsingcached(python3venv)$pipinstallpip-toolsCollectingpip-toolsDownloading(43kB)100%|████████████████████████████████|51/sCollectingsix(frompip-tools)Usingcached;=6(frompip-tools)Usingcached

创建一个名为的文件,在其中写上需要的模块及其版版本,比如arrow和flask,版本如下:

(python3venv)$==0.13.1Flask==1.0.2EOF

然后,使用pip-compile(是pip-tools中提供的),依据创建文件

(python3venv)$==0.13.1\--hash=sha256:3397e5448952e18e1295bf047014659effa5ae8da6a5371d37ff0ddc46fa6872\--hash=sha256:6f54d9f016c0b7811fac9fb8c2c7fa7421d80c54dbdd75ffb12913c55db60b8aclick==7.0\--hash=sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13\--hash=sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7\viaflaskjinja2==2.10\--hash=sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd\--hash=sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4\viajinja2python-dateutil==2.8.0\--hash=sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb\--hash=sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e\viapython-dateutilwerkzeug==0.14.1\--hash=sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c\--hash=sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b\Toupdate,run:==1.12.0\--hash=sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c\--hash=sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73\#viapython-dateutil(python3venv)$:::::(python3venv)$pipfreezearrow==0.13.1Click==7.0pip-tools==3.4.0python-dateutil==2.8.0six==1.12.0
指定PyPi库

如果需要将虚拟环境与特定的PyPi库关联起来,即要求安装指定的PyP中的模块或者库,为此需要在虚拟环境的根目录下创建一个名为的配置文件,在这个文件中声明安装依赖的属性。下面是一个的例子,要根据需要修改。

[global]disable-pip-version-check=Truetrusted-host==
创建虚拟环境中模块的轮子

在《必须升级pip,为什么?!》中曾经介绍了.whl文件的作用,虚拟环境中安装的模块,也可以编译为.whil文件,如果在另外一台机器上再安装同样模块,只需要用pip安装此文件即可,从而让虚拟环境的移植更简单了。

具体操作流程如下所示。

(python3venv)$pipwheel--wheel-dir=/tmp/==0.13.1((line7))Usingcached((line10))Usingcached((line14))Usingcached(python3venv)$ls/tmp/_(python3venv)$pipuninstallarrowpython_:Wouldremove:/Users/james/python3venv/lib//site-packages//*/Users/james/python3venv/lib//site-packages/arrow/*Proceed(y/n)?:Wouldremove:/Users/james/python3venv/lib//site-packages/dateutil/*/Users/james/python3venv/lib//site-packages/python_/*Proceed(y/n)?:Wouldremove:/Users/james/python3venv/lib//site-packages//*/Users/james/python3venv/lib//site-packages/(y/n)?(python3venv)$pipinstall--find-links=/tmp/:/tmp/wheel-dirCollectingarrow==0.13.1((line7))Collectingpython-dateutil==2.8.0((line10))Collectingsix==1.12.0((line14))Installingcollectedpackages:six,python-dateutil,
结束语

创建虚拟环境的目的,就是隔离特定模块的版本,从而满足不同项目的特定需要

另外,除了上述创建虚拟环境的方法之外,现在也流行着一个名为pipenv的模块,有兴趣的可以试试,代码仓库地址:。当然,对它也是仁者见仁智者见智。