全文共5308字,预计学习时长20分钟或更长
依附之门:“放弃进入这里的所有希望。”
插图:Gustave Doré
Python的虚拟环境极大地方便了人们的生活。本指南先介绍虚拟环境的基础知识以及使用方法,然后再深入介绍虚拟环境背后的工作原理。
注意:本指南在macOS Mojave系统上使用最新版本的Python 3.7.x。
目录
· 为什么使用虚拟环境?
· 什么是虚拟环境?
· 使用虚拟环境
· 管理环境
· 虚拟环境如何执行?
1. 为什么使用虚拟环境?
虚拟环境为一系列潜在问题提供简单的解决方案,尤其是在以下几个方面:
· 允许不同的专案使用不同版本的程式包,从而解决依赖性问题。例如,可以将Project A v2.7用于Project X,并将Package A v1.3用于Project Y。
· 通过捕获需求档案中的所有包依赖项,使专案自包含且可重现。
· 在没有管理员许可权的主机上安装软件包。
· 只需要一个专案,无需在系统范围内安装软件包,就能保持全域性site-packages /目录整洁。
听起来很方便,不是吗?开始构建更复杂的专案并与其他人协作时,虚拟环境的重要性会凸显出来。很多资料科学家也需要熟悉虚拟环境中与多语言相关的Conda环境。
可按照先后次序来使用!
2. 什么是虚拟环境?
到底什么是虚拟环境?
虚拟环境是用于依赖项管理和专案隔离的Python工具,允许Python站点包(第三方库)安装在本地特定专案的隔离目录中,而不是全域性安装(即作为系统范围内的Python的一部分)。
这听起来不错,但到底什么是虚拟环境呢?虚拟环境只是一个包含三个重要元件的目录:
· 安装了第三方库的site-packages /资料夹。
· 系统上安装的Python可执行档案的symlink符号连结。
· 确保执行Python程式码的指令码使用在给定虚拟环境中安装的Python直译器和站点包。
最后一点在于会发生一些意想不到的错误,稍后会讲这一点,但现在先看看在实际中如何实际使用虚拟环境。
但丁《神曲·地狱篇》第六章—维吉尔安抚Cerberus
插图:Gustave Doré
3. 使用虚拟环境
创造虚拟环境
假设想要为正在处理的专案建立一个名为test-project/的虚拟环境,该专案具有以下目录树:
test-project/
├── data
├── deliver # Final analysis, code, & presentations
├── develop # Notebooks for exploratory analysis
├── src # Scripts & local project modules
└── tests
需要执行venv模组,它是Python标准库的一部分。
% cd test-project/
% python3 -m venv venv/ # Creates an environment called venv/
注意:可使用不同的环境名称替换“venv/”。
瞧!虚拟环境诞生了。现在专案变成:
test-project/
├── data
├── deliver
├── develop
├── src
├── tests
└── venv # There it is!
提醒:虚拟环境本身就是一个目录。
唯一要做的事情是通过执行前面提到的指令码来“启用”环境。
% source venv/bin/activate
(venv) % # Fancy new command prompt
现在我们位于活动的虚拟环境中(由命令提示符指示,字首为活动环境的名称)。
我们会像往常一样处理专案,确保专案与系统的其他部分完全隔离。在虚拟环境中,我们无法访问系统范围的站点包,并且无法在虚拟环境之外访问安装包。
完成专案工作时,可以通过以下程式码退出环境:
(venv) % deactivate
% # Old familiar command prompt
安装包
预设情况下,只在新环境中安装pip和setuptools。
(venv) % pip list # Inside an active environmentPackage Version
---------- -------
pip 19.1.1
setuptools 40.8.0
如果想要安装第三方库的特定版本,比如numpyv1.15.3,可像往常一样使用pip。
(venv) % pip install numpy==1.15.3
(venv) % pip listPackage Version
---------- -------
numpy 1.15.3
pip 19.1.1
setuptools 40.8.0
现在可在指令码或活动的Python shell中汇入numpy。例如,假设专案包含以下几行指令码tests / imports-test.py。
#!/usr/bin/env python3
import numpy as np
直接从命令列执行这个指令码时,可得到:
(venv) % tests/imports-test.py
(venv) % # Look, Ma, no errors!
成功。指令码汇入numpy没有故障。
但丁和Virgil穿过Styx河—但丁《神曲·地狱篇》第八章
插图:Gustave Doré
4. 管理环境
需求档案
使我们的工作成果可被他人重新使用的最简单方法是在专案的根目录(顶层目录)中加入一个需求档案。为此,需要执行pip freeze,以下列出已安装的第三方软件包及其版本号:
(venv) % pip freeze
numpy==1.15.3
并将输出写入档案,我们称之为requirements.txt。
(venv) % pip freeze > requirements.txt
更新软件包或安装新软件包时,都可使用相同的命令重写需求档案。
现在,任何共享专案的人都可以使用requirements.txt档案,通过复制环境以在系统上执行专案。
复制环境
等等——究竟是怎么做到的?
想象一下,我们的队友Sara从团队的GitHub储存库中删除了测试专案。在她的系统上,专案的目录树如下所示:
test-project/
├── data
├── deliver
├── develop
├── requirements.txt
├── src
└── tests
注意到有点不寻常的东西了吗?是的,没错!没有venv /资料夹。
我们已经将它从团队的GitHub储存库中删除,因为它的存在可能会引起麻烦。
这就是使用requirements.txt档案对复制专案程式码至关重要的一个原因。
要在机器上执行测试专案,Sara需要做的就是在专案的根目录中建立一个虚拟环境:
Sara% cd test-project/
Sara% python3 -m venv venv/
并使用pip install -r requirements.txt将专案的依赖项安装在活动的虚拟环境中。
Sara% source venv/bin/activate
(venv) Sara% pip install -r requirements.txt
Collecting numpy==1.15.3 (from -r i (line 1))
Installing collected packages: numpy
Successfully installed numpy-1.15.3
现在,Sara系统上的专案环境与我们的系统完全相同。很整洁,不是吗?
故障排除
可惜事情并不总是按计划进行,总会遇到一些问题。也许错误地更新了特定的站点包后发现自己处于Dependency Hell的第九级,无法执行单行专案程式码。也许它没那么糟糕,可能你会发现自己竟处于第七级。
无论你发现自己处于何种程度,解决问题并再次看到希望的最简单方法是重新建立专案的虚拟环境。
% rm -r venv/ # Nukes the old environment
% python3 -m venv venv/ # Makes a blank new one
% pip install -r requirements.txt # Re-installs dependencies
大功告成,多亏了requirements.txt档案,又恢复了正常。然而另一个原因是始终要在专案中列入需求档案。
但丁与冰中的叛徒对话——但丁《神曲·地狱篇》第32章
插图:Gustave Doré
5. 虚拟环境如何做到这一点?
想了解更多有关虚拟环境的资讯吗?比如,活动环境如何使用正确的Python解释程式并如何找到合适的第三方库?
echo $ PATH
这一切都归结为PATH的价值,它告诉shell使用什么Python例项以及在哪里寻找网站包。在基础shell中,PATH看起来或多或少是这样表现的。
% echo $PATH
/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
呼叫Python直译器或执行.py指令码时,shell会按顺序搜寻PATH中列出的目录,直到遇到Python例项。要检视PATH首先找到的Python例项,请执行which python3。
% which python3
/usr/local/bin/python3 # Your output may differ
通过站点模组(这是Python标准库的一部分)查询此Python例项查询站点包的位置也很容易。
% python3 # Activates a Python shell
>>> import site
>>> site.getsitepackages() # Points to site-packages folder['/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages']
执行指令码venv / bin / activate修改PATH,以便shell在搜寻系统的全域性二进位制档案之前搜寻专案的本地二进位制档案。
% cd ~/test-project/
% source venv/bin/activate
(ven) % echo $PATH~/test-project/venv/bin:/usr/local/bin:/usr/bin:/usr/sbin:/bin:/sbin
现在shell知道如何使用专案的本地Python例项:
(venv) % which python3
~/test-project/venv/bin/python3
在哪里可以找到专案的本地站点包?
(venv) % python3
>>> import site
>>> site.getsitepackages()['~/test-project/venv/lib/python3.7/site-packages'] # Ka-ching
理智检查
还记得以前的tests / imports-test.py指令码吗?看起来是下面这样:
#!/usr/bin/env python3
import numpy as np
我们能够在活动环境中执行此指令码,不出现任何问题,是因为环境中的Python例项能够访问专案的本地站点包。
如果执行从专案的虚拟环境外部而来的相同指令码会发生什么?
% tests/imports-test.py # Look, no active environmentTraceback (most recent call last):
File "tests/imports-test.py", line 3, in
import numpy as npModuleNotFoundError: No module named 'numpy'
是的,出现了一个错误,但我们应该这样做。如果我们不这样做,那就意味着我们能够从专案外部访问专案的本地站点包,从而破坏了拥有虚拟环境的整个目的。出现错误的事实证明我们的专案与系统的其他部分完全隔离。
环境的目录树
有一件事可以帮助整理所有这些资讯,即清楚地了解环境目录树的外观。
test-project/venv/ # Our environment's root directory
├── bin
│ ├── activate # Scripts to activate
│ ├── activate.csh # our project's
│ ├── activate.fish # virtual environment.
│ ├── easy_install
│ ├── easy_install-3.7
│ ├── pip
│ ├── pip3
│ ├── pip3.7
│ ├── python -> /usr/local/bin/python # Symlinks to system-wide
│ └── python3 -> python3.7 # Python instances.
├── include
├── lib
│ └── python3.7
│ └── site-packages # Stores local site packages
└── pyvenv.cfg
但丁和维吉尔回到了人世间——但丁《神曲·地狱篇》第34章
插图:Gustave Doré
留言 点赞 关注
我们一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”