虚拟环境环境的特点
- Python版本固定。即使系统的Python升级了,虚拟环境中的仍然不受影响,保留开发状态。
- 所有Python软件包,都只在这个环境生效。一旦退出,则回到用户+系统的默认环境中。
这两个特点,由两个小手段实现。
- 改变当前Shell的
PATH
。 - 改变Python运行时的
sys.path
。
以下为python:alpine
镜像中,以root
用户演示的例子。
改变PATH
首先看一下它的目录结构:
# ls venv bin include lib # ls /usr/local bin include lib share
环境内所有的新内容,都在这个新生成目录下。 bin
是可执行文件的位置,include
是C/C++的头文件位置,lib
是库文件位置。 它和/usr/local
内的主要目录几乎相同,也和~/.local
下类似。
魔法都在两个PATH
中。
# echo $PATH /usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # . venv/bin/activate (venv) # echo $PATH /root/venv/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
显然,这个activate
,为当前PATH
增加了venv/bin
这个位置在最前方,因此虚拟环境中的可执行文件拥有最高优先级。 而lib
与include
,仅仅是bin
下面的可执行文件做相对路径运算来寻找的位置。 所以,改变了PATH
,就改变了很多事。
# ls -hl venv/bin/ total 88 -rw-r--r-- 1 root root 2.0K Mar 31 08:06 activate -rw-r--r-- 1 root root 1.1K Mar 31 08:06 activate.csh -rw-r--r-- 1 root root 3.0K Mar 31 08:06 activate.fish -rw-r--r-- 1 root root 1.5K Mar 31 08:06 activate.ps1 -rw-r--r-- 1 root root 986 Mar 31 08:06 activate.xsh -rw-r--r-- 1 root root 1.5K Mar 31 08:06 activate_this.py -rwxr-xr-x 1 root root 238 Mar 31 08:06 easy_install -rwxr-xr-x 1 root root 238 Mar 31 08:06 easy_install-3.7 -rwxr-xr-x 1 root root 220 Mar 31 08:06 pip -rwxr-xr-x 1 root root 220 Mar 31 08:06 pip3 -rwxr-xr-x 1 root root 220 Mar 31 08:06 pip3.7 -rwxr-xr-x 1 root root 35.8K Mar 31 08:06 python -rwxr-xr-x 1 root root 2.3K Mar 31 08:06 python-config lrwxrwxrwx 1 root root 6 Mar 31 08:06 python3 -> python lrwxrwxrwx 1 root root 6 Mar 31 08:06 python3.7 -> python -rwxr-xr-x 1 root root 216 Mar 31 08:06 wheel
由于优先级最高,所以环境里的python
、pip
等,包括后来用pip
安装的可执行文件,都使用的是venv
下的。
改变sys.path
(venv) # python -m site sys.path = [ '/root', '/root/venv/lib/python37.zip', '/root/venv/lib/python3.7', '/root/venv/lib/python3.7/lib-dynload', '/usr/local/lib/python3.7', '/root/venv/lib/python3.7/site-packages', ] USER_BASE: '/root/.local' (doesn't exist) USER_SITE: '/root/.local/lib/python3.7/site-packages' (doesn't exist) ENABLE_USER_SITE: False (venv) # deactivate # python -m site sys.path = [ '/root', '/usr/local/lib/python37.zip', '/usr/local/lib/python3.7', '/usr/local/lib/python3.7/lib-dynload', '/usr/local/lib/python3.7/site-packages', ] USER_BASE: '/root/.local' (doesn't exist) USER_SITE: '/root/.local/lib/python3.7/site-packages' (doesn't exist) ENABLE_USER_SITE: True
可见,sys.path
发生了翻天覆地的变化。 除了当前路径/root
和标准库/usr/local/lib/python3.7
被保留以外,其它位置都换成了venv
下的。 这就是为什么pip list
看不见什么软件包的原因,也是环境隔离的最大秘密。