Python虛擬環境詳解

Python虛擬環境詳解

和其他大多數現代編程語言一樣,Python對包和模塊的下載、存儲以及管理有其自己的一套方法。Python的包一般存在幾個地方。比如,大部分系統包會存在sys.prefix指定的路徑下。在Mac OS X下這個路徑為:

>>> import sys

>>> sys.prefix

'/System/Library/Frameworks/Python.framework/Versions/3.5'

通常情況下我們更關心第三方包的安裝位置,比如easy_install或pip會將包存放在 site.getsitepackages所指定的路徑下:

>>> import site

>>> site.getsitepackages()

[

'/System/Library/Frameworks/Python.framework/Versions/3.5/Extras/lib/python',

'/Library/Python/3.5/site-packages'

]

這裡就帶來了一個問題,當我們同時開發多個工程時,不同的工程會將第三方的包存放在相同的路徑下。這就意味著,如果有兩個工程依賴同一個包,但是所需要的版本卻不一樣,比如工程A依賴v1.0.0,而工程B依賴v2.0.0。由於Python無法根據版本來區分包的安裝路徑,所以這裡就會發生版本衝突。這也就是本文所要介紹的虛擬環境(virtualenv/venv)所要解決的問題。

什麼是虛擬環境?

Python虛擬環境的主要目的是為了給不同的工程創建互相獨立的運行環境。在虛擬環境下,每一個工程都有自己的依賴包,而與其它的工程無關。不同的虛擬環境中同一個包可以有不同的版本。並且,虛擬環境的數量沒有限制,我們可以輕鬆地用virtualenv或者pyenv等工具來創建多個虛擬環境。

虛擬環境的使用

安裝虛擬環境工具的方法非常簡單,

$ pip install virtualenv

然後,我們創建一個名字叫“env”的虛擬環境:

$ virtualenv env

這條命令會自動創建一個叫“env”的目錄,並在其中生成如下的目錄結構:

├── bin

│ ├── activate

│ ├── activate.csh

│ ├── activate.fish

│ ├── easy_install

│ ├── easy_install-3.5

│ ├── pip

│ ├── pip3

│ ├── pip3.5

│ ├── python -> python3.5

│ ├── python3 -> python3.5

│ └── python3.5 -> /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5

├── include

├── lib

│ └── python3.5

│ └── site-packages

└── pyvenv.cfg

這些目錄包括:

  • bin: 用於管理虛擬環境的文件
  • include: 編譯Python包時所需要的C頭文件
  • lib: Python自帶及第三方的庫

這其中還包含有一些Python的工具和可執行文件等副本。這些文件用來保證Python代碼可以獨立於系統環境而運行。

bin目錄下有一個重要的腳本文件activate,這個腳本就是用來將其所在的虛擬環境設置為當前Python的運行環境:

$ source env/bin/activate

(env) $

可以看到,在運行完這行命令後,shell的提示符前會出現虛擬環境的名字,表示我們已經進入了這個環境中。

為了驗證這一點,我們以bcrypt模塊為例。首先我們要在全局系統環境中安裝這個模塊。在測試之前,我們需要先通過deactivate命令退出當前的虛擬環境:

(env) $ deactivate

$

現在我們的shell提示符迴歸到了正常狀態,同時Python的環境也切換到了全局的系統環境。

現在我們來安裝bcrypt並用它來生成一個密碼的hash值:

$ pip -q install bcrypt

$ python -c "import bcrypt; print(bcrypt.hashpw('password'.encode('utf-8'), bcrypt.gensalt()))"

$2b$12$vWa/VSvxxyQ9d.WGgVTdrell515Ctux36LCga8nM5QTW0.4w8TXXi

然後我們切換到虛擬環境並試圖運行同樣的命令:

$ source env/bin/activate

(env) $ python -c "import bcrypt; print(bcrypt.hashpw('password'.encode('utf-8'), bcrypt.gensalt()))"

Traceback (most recent call last):

File "", line 1, in

ImportError: No module named 'bcrypt'

可以看到,在虛擬環境中,bcrypt並沒有被安裝,說明虛擬環境的隔離作用是生效的。

虛擬環境是如何工作的?

瞭解虛擬環境背後的工作原理,對於一個Python開發者來說非常重要,它能夠幫助我們理解Python的運行環境,對依賴的解析等技術。為了解釋虛擬環境的原理,我們先來看一下在不同的環境中,Python可執行文件的位置有什麼不同。在默認的系統環境中查看python的路徑:

$ which python

/usr/bin/python

然後我們進入虛擬環境

$ source env/bin/activate

(env) $ which python

/Users/michaelherman/python-virtual-environments/env/bin/python

可以看到,在激活虛擬環境後,python可執行文件的路徑變成了當前環境目錄下的路徑,並且$PATH也發生了變化:

$ echo $PATH

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

$ source env/bin/activate

(env) $ echo $PATH

/Users/michaelherman/python-virtual-environments/env/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:

虛擬環境下的bin目錄排在了$PATH的最前面。這意味著,用戶在命令行中執行python的時候,將率先使用虛擬環境下的可執行文件,而不是系統默認的。

那麼虛擬環境下的python可執行文件與系統默認的有什麼不同呢?Python又是如何找到虛擬環境下的第三方庫的呢?

事實上,上面提到的python可執行文件之間並沒有什麼不同,但是它們所在的位置至關重要。在Python啟動的時候,它會獲取自身所在的路徑。然後這一路徑(bin的上一級)被設置到sys.prefix和sys.exec_prefix之中。在搜索第三方的site-packages時,搜索目錄是sys.prefix所指向的路徑下的lib/pythonX.X/site-packages/,其中X.X是Python的版本。

在前面的例子中,python文件所在路徑為/Users/michaelherman/python-virtual-environments/env/bin,因此sys.prefix會被設為/Users/michaelherman/python-virtual-environments/env,從而site-packages的路徑就變成了/Users/michaelherman/python-virtual-environments/env/lib/pythonX.X/site-packages。最後,這一路徑被存儲在sys.path數組中,其中包含著所有包的引用來源。

使用virtualenvwrapper管理虛擬環境

虛擬環境的引入解決了我們關於環境衝突的問題,但是它同時也帶來了一個問題,就是虛擬環境過多所帶來的管理問題。virtualenvwrapper就是專門用來解決虛擬環境管理問題的一個工具。我們可以很方便地用它來實現對虛擬環境的創建,刪除,拷貝,並且可以輕鬆地在不同環境間進行切換。

virtualenvwrapper的安裝非常簡單:

$ pip install virtualenvwrapper

安裝後,我們需要將virtualenvwrapper.sh腳本添加到shell啟動文件中:

$ which virtualenvwrapper.sh

/usr/local/bin/virtualenvwrapper.sh

在shell啟動文件~/.bashrc中添加:

export WORKON_HOME=$HOME/.virtualenvs # Optional

export PROJECT_HOME=$HOME/projects # Optional

source /usr/local/bin/virtualenvwrapper.sh

並運行

$ source ~/.bashrc

然後就會在$WORKON_HOME所在的路徑下創建集中存放虛擬環境的目錄。

接著,我們就可以用下面的一系列命令虛擬環境進行管理:

workon

deactivate

mkvirtualenv

cdvirtualenv

rmvirtualenv

比如,我們要創建一個新的工程:

$ mkvirtualenv my-new-project

(my-new-project) $

此時會在$WORKON_HOME下創建一個新的虛擬環境。

退出一個虛擬環境的方法和之前一樣:

(my-new-project) $ deactivate

$

如果你有多個虛擬環境,可以對它們進行查看:

$ workon

my-new-project

my-django-project

web-scraper

並選擇其中一個進行激活:

$ workon web-scraper

(web-scraper) $

這樣,你就不再需要記住每一個環境存放的具體位置,可以輕鬆的對他們進行刪除、拷貝、切換,是不是非常方便?

好了,關於虛擬環境的介紹就到這裡,獲取更多精彩內容敬請關注。


分享到:


相關文章: