理解Python虚拟环境
努力把事讲清楚
107 人赞同了该文章
什么是环境
既然有所谓的 虚拟环境(Virtual Environment),那么首先有必要解释一下,什么是环境。
这里的环境,指的就是 Python 代码的运行环境。它应该包含以下信息:
- Python 解释器,用哪个解释器来执行代码?
- Python 库的位置,该去哪里
import
所需要的模块呢? - 可执行程序的位置,比如说安装了
pip
,那么pip
命令是在哪里呢?
其中第 1 个是最主要的,后面 2 个基本是围绕它确定的。
如果看了我在 安装 Python 详解 里对安装后的文件夹的说明,应该很清楚了,就是:
python.exe
-
Lib
文件夹,包括其中的site-packages
-
Scripts
文件夹
sys.path
当我们说包的路径就在 Lib
和 site-packages
文件夹里的时候,虽然大多数的情况下就是这样的,但是实际上并不准确。
包的搜寻路径是通过 Python 系统中的一个变量决定的,也就是 sys.path
,我们先来打印一下看看:
>>> import sys
>>> from pprint import pprint
>>> pprint(sys.path)
['', # 注意,别忽视了第 1 个
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\DLLs',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\lib',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38',
'C:\\Users\\Davy\\AppData\\Roaming\\Python\\Python38\\site-packages',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages']
>>>
“
pprint
是内置的 pretty-print 模块,可以自动换行,让打印结果好看一点。
注意:第 1 项是一个空字符串,它代表的是当前路径,也就是你启动程序的地方。比如说,我们默认情况下进入命令行就自动进入到当前用户的目录,例如 C:\Users\Davy
,那么当前目录就是这个。
如果你还感到疑惑,可以用下面的语句打印出绝对路径:
>>> import os.path
>>> os.path.abspath('')
'C:\\Users\\Davy'
除了第一项,这个列表里最常用的就是最后一项,这个在 Python 安装详解 中有过说明。
什么是虚拟环境
知道了什么是环境,再来理解什么是虚拟环境就非常容易了。
简而言之,虚拟环境就是 Python 环境的一个副本。
要得到这么一个副本,首先:
- 要给它单独找个文件夹存起来
- 要给它取个名字
这个文件夹的名字也就是这个虚拟环境的名字,在这个文件夹下面有这些东西:
- 一个
python.exe
- 一个
Scripts
目录 - 一个
Lib
目录
这里和普通环境有 2 点不一样的地方:
-
python.exe
也放在了Scripts
目录下面(原因下面会讲) -
Lib
目录下面只有site-packages
目录
让我们来试一下。
venv
模块
在 Python 2.x 的时候,创建虚拟环境还需要安装第三方的 virtualenv
,但是自从 Python 3.3 版本之后,标准库里内置了 venv
模块,可以用来创建虚拟环境。
在命令行中使用下面的命令来快速创建一个虚拟环境:
C:\Users\Davy>python -m venv venvdemo
上面的命令会在当前目录下,新建一个名为 venvdemo
的虚拟环境。里面的文件夹:
其中 Include
基本不用管,Lib
目录下也没什么特别的,主要就是 Scripts
目录:
其中多出了 activate
和 deactivate
用来 激活 和 去激活 虚拟环境。
“
activate
有多个后缀的文件,适配多个环境,敲命令的时候不需要带后缀
让我们来激活试试:
C:\Users\Davy>venvdemo\Scripts\activate
注意到一点,激活的时候我们需要指定 activate
完整的路径,因为它所在的目录并不在 PATH
环境变量之中。
激活之后,我们就进入了虚拟环境,这时候不管是执行 python
还是 pip
针对的都是虚拟环境里面的。
其实这也没什么神奇的操作,激活只不过就是把虚拟环境的 Scripts
目录临时添加到了 PATH
环境变量的第一位。
这里也解释了,为啥要把 python.exe
也放到了 Scripts
目录下,因为这样只需要加一个路径到环境变量中即可。
同时这也提醒我们注意,不是只有激活才能进入虚拟环境,我们如果把当前路径切换到了虚拟环境的 Scripts
目录下,启动 python
也是在虚拟环境中了。
继续打印一下 sys.path
看看:
(venvdemo) C:\Users\Davy>python
Python 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 23:11:46) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from pprint import pprint
>>> import sys
>>> pprint(sys.path)
['',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\python38.zip',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\DLLs',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\lib',
'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38',
'C:\\Users\\Davy\\venvdemo',
'C:\\Users\\Davy\\venvdemo\\lib\\site-packages']
可以看到相对于上面普通的系统环境,最下面的两条发生了变化,注意其中的第 4 条路径 'C:\\Users\\Davy\\AppData\\Local\\Programs\\Python\\Python38\\lib'
,它正是标准库的路径。
我们在执行去激活的时候,就不用再指定完整的路径了。
为什么要有虚拟环境
当我们安装一个 Python 程序或者库的时候,一般情况下我们虽然是想要安装 1 个包,比如说, pip install django
。然而实际安装的都是一堆包。这些包默认都会安装到 Python 环境的 site-packages
目录下面。
下次再安装其它包时,也是如此。因为同一个库,只能在一个环境中存在一份,那么这其中如果发现了某个依赖包已经存在,只能大家公用。
这样下去,说不定哪一天这中间就出现了版本不兼容。
使用虚拟环境
因为虚拟环境的必要性,现在大多数的 Python 开发工具都支持虚拟环境的相关操作。
具体每个工具有所不同,但是一般只需要注意一点即可:指定虚拟环境中 python.exe
的位置。一旦确定了它的位置,就确定了环境的位置。也就不用每次都去激活。
“ 仔细观察,虚拟环境中的
python.exe
和系统中的python.exe
并不完全一样。
保存虚拟环境
我们知道在使用 pip install
的时候可以通过 -r
选项指定一个 requirements
文件,这样就能批量安装所有依赖。
在 requirements
里面可以精确的指定安装包版本,有效地避免不兼容问题。
执行 pip freeze
可以把当前环境安装的包以 requirements
的格式输出。
(venvdemo) C:\Users\Davy>pip freeze
asgiref==3.2.3
Django==3.0.3
pytz==2019.3
sqlparse==0.3.0
把输出结果保存到文件中就可以了,这样我们就精确的得到当前环境的版本信息,可以再其它地方重建这个环境。