Python虛擬環境指南2019版
這是一篇舊文,編寫於2017年,用於公司內部交流。整理更新後於2019年04月06日重發,內容有效期樂觀估計半年,閱讀請注意保質期。
為什麼用python虛擬環境
python版本差異
python當前主要有2個release版本Python 2.7.16 和Python 3.7.3 ,這兩個版本在一些語法上存在較大差異。
如果你從網上下載了一段python程式碼,卻執行不起來,首先要排除的是python版本問題。比如下面這個hello_python.py
,程式碼非常簡單,就一句列印hello,world
到螢幕上。
print "hello,world" 複製程式碼
如果你使用python2.7,恭喜你可以很好的跑起來,如下:
(python27) ➜python hello_python.py hello,world 複製程式碼
如果你使用的是python3,可能就實現從入門到放棄:(
(python37) ➜python hello_python.py File "hello_python.py", line 3 print "hello,world" ^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print("hello,world")? 複製程式碼
python3 中讓程式碼正常執行的辦法和提示一樣,修改語句為print("hello,world")
python2.7已經“過時” ,pip執行是會提示:
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. 複製程式碼
現實狀況卻是一些庫的版本問題或者歷史遺留問題,可能需要在python2和python3之間切換。
python使用場景差異
python語言應用非常廣泛,涉及伺服器指令碼、爬蟲、程式開發、科學計算,大資料,機器學習等。不同的場景下,使用的庫是有差異:
使用場景 | 常用庫 |
---|---|
程式開發 | flask/django |
爬蟲 | requests/beautifulsoup4/scrapy |
科學計算 | pandas/numpy/matplotlib |
... | ... |
庫又會依賴另外的庫,這樣如果全部安裝在一個環境裡,難以規避庫的版本衝突。
鑑於python版本差異和使用場景差異,推薦使用虛擬環境進行隔離管理,省事不少。
怎麼使用虛擬環境
使用 pip
使用虛擬環境之前,我們先花一點點時間來了解python的包安裝工具pip , 相信我這很簡單。
Python的最大的優勢之一是豐富的庫,跨平臺,在UNIX,Windows和Macintosh相容很好。
安裝這些庫,讓開發速度飈起來,就需要使用pip 。
下面使用pip
安裝requests
庫示例:
(py27studio) ➜pytest pip install requests Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Collecting requests Downloading https://pypi.tuna.tsinghua.edu.cn/packages/f1/ca/10332a30cb25b627192b4ea272c351bce3ca1091e541245cccbace6051d8/requests-2.20.0-py2.py3-none-any.whl (60kB) 100% |████████████████████████████████| 61kB 1.5MB/s Collecting chardet<3.1.0,>=3.0.2 (from requests) Using cached https://pypi.tuna.tsinghua.edu.cn/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl Collecting urllib3<1.25,>=1.21.1 (from requests) Downloading https://pypi.tuna.tsinghua.edu.cn/packages/62/00/ee1d7de624db8ba7090d1226aebefab96a2c71cd5cfa7629d6ad3f61b79e/urllib3-1.24.1-py2.py3-none-any.whl (118kB) 100% |████████████████████████████████| 122kB 1.5MB/s Collecting certifi>=2017.4.17 (from requests) Downloading https://pypi.tuna.tsinghua.edu.cn/packages/56/9d/1d02dd80bc4cd955f98980f28c5ee2200e1209292d5f9e9cc8d030d18655/certifi-2018.10.15-py2.py3-none-any.whl (146kB) 100% |████████████████████████████████| 153kB 287kB/s Collecting idna<2.8,>=2.5 (from requests) Downloading https://pypi.tuna.tsinghua.edu.cn/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl (58kB) 100% |████████████████████████████████| 61kB 131kB/s Installing collected packages: chardet, urllib3, certifi, idna, requests Successfully installed certifi-2018.10.15 chardet-3.0.4 idna-2.7 requests-2.20.0 urllib3-1.24.1 複製程式碼
從示例可見pip 的2個特點:
-
快速安裝。命令列中一鍵安裝完成。
-
自動解決依賴。在安裝requests的同時還安裝了: chardet, urllib3, certifi, idna 並且自動解決各個庫的版本問題, 一般情況下我們不用關心這些細節。
下面是pip 的一些常用命令
# 列出庫列表 pip list # 升級pip pip install pip -U # 安裝指定的庫 pip install name # 刪除指定的庫 pip uninstall name 複製程式碼
瞭解pip 的常用命令後,可以愉快的寫程式碼了。逐漸你會遇到在不同機器上同步庫或者同事使用你的程式碼,需要安裝相同的庫。這時候你就需要pip 的2個進階命令了。
# 將當期環境中的庫列表形成 requirements.txt 檔案 pip freeze >requirements.txt # 根據 requirements.txt 批量安裝庫 pip install -r requirements.txt 複製程式碼
你可以使用下面2個命令,獲取pip 的使用幫助,瞭解更多
pip help pip install -h 複製程式碼
由於PyPI 服務位於國外,訪問起來比較緩慢,可以使用國內的一些源進行加速
設定pip使用國內源 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 複製程式碼
一些其它的源: 豆瓣源:pypi.douban.com/simple/ 阿里雲源:mirrors.aliyun.com/pypi/simple…
其它平臺/語言也有類似的解決方案,如果你有興趣可以使用下面關鍵字自行了解。
yum/apt/npm/brew/maven...
使用 venv
Python 從3.3 版本開始,自帶了一個虛擬環境 venv,在PEP-405 中可以看到它的詳細介紹。
在 *nix 系統上,可以直接執行pyvenv ./blog-env
來建立一個虛擬環境。在 Windows 系統上,則可以使用python -m venv ./blog-env
來建立, 這個命令也可以用於 *nix 系統,推薦使用。
venv建立的虛擬環境,建議就在專案目錄,這樣使用起來更方便,沒有記憶負擔。
建立完成後 *nix 系統上, 使用source ./blog-env/bin/activate
進入虛擬環境,window系統上,使用Scripts\\activate.bat
,效果如下:
➜blog source ./blog-env/bin/activate (blog-env) ➜blog 複製程式碼
注意在命令提示符之前新出現的(blog-env) 標識進入了新的虛擬環境。
這樣很方便就獲得了一個隔離的python環境。
使用 pipenv
pipenv是Kenneth Reitz 推出的python包依賴工具, kr就是大名鼎鼎requests 的作者。pipenv號稱Python Dev Workflow for Humans , 實力可見一斑。
介紹pipenv 之前,我們先看venv 存在的問題。我這裡有一個django專案,使用django-rest-framework提供RestFul api服務, 利用jwt進行前後端認證,專案安裝完後依賴大概如下:
(wxsc) ➜wordpress pip list PackageVersion ----------------------- ---------- asn1crypto0.24.0 certifi2018.10.15 cffi1.11.5 chardet3.0.4 coreapi2.3.3 coreschema0.0.4 cryptography2.3.1 diff-match-patch20181111 Django2.0.5 django-crispy-forms1.7.2 django-filter2.0.0 django-formtools2.1 django-import-export1.1.0 django-reversion3.0.0 djangorestframework3.9.0 djangorestframework-jwt 1.11.0 et-xmlfile1.0.1 future0.16.0 httpie1.0.0 httplib20.12.0 idna2.7 itypes1.1.0 jdcal1.4 Jinja22.10 Markdown3.0.1 MarkupSafe1.1.0 odfpy1.3.6 openpyxl2.5.10 pip18.1 pipenv2018.11.14 pycparser2.19 Pygments2.2.0 PyJWT1.6.4 PyMySQL0.9.2 pytz2018.5 PyYAML3.13 requests2.20.1 setuptools40.6.2 six1.11.0 tablib0.12.1 unicodecsv0.14.1 uritemplate3.0.0 urllib31.24.1 virtualenv16.1.0 virtualenv-clone0.4.0 wheel0.32.2 xlrd1.1.0 XlsxWriter1.1.2 xlwt1.3.0 複製程式碼
前前後後大約安裝了50個包,最後完全不清楚,那些是我直接安裝的,那些是間接安裝的,pipenv 可以解決這個問題。
pipenv安裝很方便:
$ pip install pipenv 複製程式碼
如果標準版本還是python2.7,則可以使用 pip3 install pipenv
pipenv使用起來也很方便。接下來我們一起了解這個過程。
建立一個新的工作目錄myproject
,使用下面命令建立虛擬環境,建立完成後目錄下會生成一個Pipfile檔案。
$ pipenv --three Creating a virtualenv for this project… Pipfile: /private/tmp/myproject/Pipfile Using /Library/Frameworks/Python.framework/Versions/3.7/bin/python3 (3.7.1) to create virtualenv… ✔ Complete Using base prefix '/Library/Frameworks/Python.framework/Versions/3.7' New python executable in /Users/tu/codes/venv/myproject-7Ev2diGY/bin/python3 Also creating executable in /Users/tu/codes/venv/myproject-7Ev2diGY/bin/python Installing setuptools, pip, wheel... done. Running virtualenv with interpreter /Library/Frameworks/Python.framework/Versions/3.7/bin/python3 Virtualenv location: /Users/tu/codes/venv/myproject-7Ev2diGY Creating a Pipfile for this project… 複製程式碼
檢視虛擬環境的實際目錄,瞭解python命令路徑(可以用於配合pycharm選擇直譯器)。
$ pipenv --venv $ pipenv --py 複製程式碼
pipenv 的虛擬環境會統一存放,不會在專案路徑下
安裝軟體包。包安裝完成後,會在專案路徑下生成Pipfile.lock檔案。
$ pipenv install requests $ pipenv install django 複製程式碼
注意:這裡不是使用pip 進行包安裝,而是使用pipenv 。
檢視專案依賴。檢視比較清晰的描述了,專案依賴了2個包,每個包又分別依賴了其它的一些包。
➜myproject2 pipenv graph Django==2.1.3 - pytz [required: Any, installed: 2018.7] requests==2.20.1 - certifi [required: >=2017.4.17, installed: 2018.10.15] - chardet [required: >=3.0.2,<3.1.0, installed: 3.0.4] - idna [required: >=2.5,<2.8, installed: 2.7] - urllib3 [required: >=1.21.1,<1.25, installed: 1.24.1] 複製程式碼
重用requirements.txt
檔案。在專案目錄下建立requirements.txt
,內容參見上文。
$ pipenv install 複製程式碼
pipenv 預設會讀取本地目錄,也可以使用**-r**引數指定requirements.txt
位置。
pipenv 的依賴和 venv 有差異,可能直接匯入 venv中的requirements.txt
有一些問題,可以直接手工安裝。
pipenv就簡單介紹到這裡,大家可以看pipenv使用指南。總的來說venv和pipenv各有優勢吧,venv原生自帶,簡單方便,比較適合伺服器上除錯;pipenv,功能強大更適合本地除錯。
Anaconda
科學計算領域,python著名的庫pandas ,numpy 和matplotlib , 然後還有影象處理和視覺這塊的opencv ,以及機器學習的tensorflow 安裝比較複雜,在這個領域一般使用anaconda 的解決方案,其wiki介紹如下:
Anaconda 是一種Python語言的免費增值開源發行版,用於進行大規模資料處理、預測分析,和科學計算,致力於簡化包的管理和部署。 Anaconda使用軟體包管理系統Conda進行包管理。
我選擇的是anaconda3
,使用的iterm2
,安裝完成後會有路徑問題,需要在~/.zshrc
中新增:
export PATH="/anaconda3/bin:$PATH" 複製程式碼
然後訪問使用下面命令檢視anaconda環境。
➜~ which conda /anaconda3/bin/conda ➜~ conda --version conda 4.5.11 複製程式碼
建立虛擬環境,並進入虛擬環境:
conda create --name python36 python=3.6 ➜~ source activate python36 (python36) ➜~ (python36) ➜~ python -V Python 3.6.7 :: Anaconda, Inc. (python36) ➜~ source deactivate ➜~ 複製程式碼
檢視conda 管理的環境列表:
➜~ conda info -e # conda environments: # base*/anaconda3 python36/anaconda3/envs/python36 複製程式碼
Anaconda在個人研發過程中使用不多,如果想了解更多,可以看Anaconda 入門安裝教程 。
docker時代的python環境
前面介紹的內容,都是在本地進行一些配置,建立各種環境。可是本地就一個,折騰幾次後還是容易亂,docker這麼強大,我們也可以用docker來玩python開發。
首先,我們編寫hello.py
,程式碼如下:
# -*- coding:utf-8 -*- def test(): print "Hello, python, docker" if __name__ == "__main__": test() 複製程式碼
然後執行下面命令:
docker run -it --rm --name docker-python2 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:2.7.16-alpine3.9 python hello.py 複製程式碼
命令結果如下:
Unable to find image 'python:2.7.16-alpine3.9' locally 2.7.16-alpine3.9: Pulling from library/python 8e402f1a9c57: Already exists d8cdc394c05b: Pull complete 1e2b4a75cc6b: Pull complete 2fbbf60d928e: Pull complete Digest: sha256:46d6e67d464a2811efe60440248623b14cb6db273fac59631dd8bd9e13a77491 Status: Downloaded newer image for python:2.7.16-alpine3.9 Hello, python, docker 複製程式碼
注意,初次執行會進行映象檔案下載,比較緩慢,下載成功後再次執行指令碼就會非常迅速了。
這裡的docker命令比較複雜,可以先不用管它的含義。我們繼續編寫hello3.py
,程式碼如下:
# -*- coding:utf-8 -*- def test(): print("Hello, python, docker") if __name__ == "__main__": test() 複製程式碼
使用下面命令執行:
docker run -it --rm --name docker-python3 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:3.7.3-alpine3.9 python hello3.py 複製程式碼
執行結果如下:
Unable to find image 'python:3.7.3-alpine3.9' locally 3.7.3-alpine3.9: Pulling from library/python Digest: sha256:11568bb68bd375727e468ea5995f556139ff305eed9d8ee1d04b1a4a03a6486a Status: Downloaded newer image for python:3.7.3-alpine3.9 Hello, python, docker 複製程式碼
我們簡單瞭解一下執行命令的含義:
➜python docker run --help Usage:docker run [OPTIONS] IMAGE [COMMAND] [ARG...] -i, --interactiveKeep STDIN open even if not attached ... --rmAutomatically remove the container when it exits ... -t, --ttyAllocate a pseudo-TTY ... -v, --volume listBind mount a volume --volume-driver stringOptional volume driver for the container --volumes-from listMount volumes from the specified container(s) -w, --workdir stringWorking directory inside the container 複製程式碼
docker run -it --rm --name docker-python2 -v "$PWD":/usr/src/myapp -w /usr/src/myapp python:2.7.16-alpine3.9 python hello.py
翻譯過來的意思大概是下面幾點:
- 使用 python:2.7.16-alpine3.9 映象啟動容器,python表示映象名稱,2.7.16-alpine3.9表示版本標籤。
- 容器名稱命名為docker-python2,並且輸出資訊到當前終端,容器執行完成後自動刪除。
-
容器使用資料卷,將當前目錄和容器內的
/usr/src/myapp
目錄進行對映。 -
設定
/usr/src/myapp
為工作目錄,然後執行python hello.py
命令。
這樣經過上面幾步,我們就使用docker容器執行了hello.py
了。而且我們也有了2個映象,可以分別執行python2和python3的程式碼。當然實際的工程中,只是執行一個py檔案
有點殺雞用牛刀的感覺,可以如果執行一個django專案,卻是可以很好的保持開發環境和部署環境的一致。這部分內容,以後我會進行補充介紹。
提示:docker和venv/pipenv也可以配合使用,將虛擬環境建立在當前目錄即可,留給大家動手探索吧。
回顧
最後,我們一起來簡單回顧一下python虛擬環境:
- 使用python虛擬環境可以有效解決python語法版本差異及使用場景差異。
- 使用pip 安裝各種包。
- python3自帶venv 建立和管理各種環境。
- pipenv是一種混合了pip和venv的環境管理方法。
- 使用anaconda 管理python科學計算環境。
- 可以使用docker等方式使用python環境。
附錄
如果繼續使用pyhon2,可以參靠下面部分內容。python2的虛擬環境virtualenv&virtualenvwrapper。
virtualenv是一個建立隔絕的Python環境的工具,可以建立一個包含所有必要的可執行檔案的資料夾,用來使用Python工程所需的包。
virtualenv安裝非常簡單,直接使用下面命令:
pip install virtualenv 複製程式碼
可能會遇到許可權問題,可以使用sudo提權
但是virtualenv 有一個弊端是,每次會在當前目錄建立venv)(pycharm預設使用這種方式),每次需要自己記住不同的虛擬機器目錄,使用起來不太方便。 這裡我們直接跳過virtualenv 的使用,繼續使用其擴充套件包virtualenvwrapper
virtualenvwrapper安裝也非常簡單,直接使用下面命令:
pip install virtualenvwrapper 複製程式碼
! 注意:windows使用者使用的命令是 pip install virtualenvwrapper-win 後面帶**-win**
使用virtualenvwrapper
需要先設定環境變數,我使用的iTerm2
配置的zshrc
,需要在使用者根目錄下的.zshrc
中增加下面2行:
export WORKON_HOME=~/codes/venv source /usr/local/bin/virtualenvwrapper.sh 複製程式碼
配置好環境變數後,退出重啟term
生效。
建立一個flask 開發環境
mkvirtualenv flask Using base prefix '/Library/Frameworks/Python.framework/Versions/2.7' New python executable in /Users/tu/codes/venv/flask/bin/python Also creating executable in /Users/tu/codes/venv/flask/bin/python Installing setuptools, pip, wheel...done. virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/predeactivate virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/postdeactivate virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/preactivate virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/postactivate virtualenvwrapper.user_scripts creating /Users/tu/codes/venv/flask/bin/get_env_details (flask) ➜pytest 複製程式碼
注意建立好虛擬環境後會自動進入該環境,命令提示符前會顯示當前環境的名稱,例如(flask ) 字樣。
再建立一個爬蟲的開發環境
mkvirtualenv spider ... 複製程式碼
這樣你可以在flask的環境中安裝flask庫,spider的環境中安裝requests庫,而不用擔心依賴衝突。
如果你希望建立一個python3版本的環境,需要先行安裝好python3,然後使用下面命令:
# -p 引數指定版本,可以使用python3的絕對路徑 mkvirtualenv py3studio -p python3 複製程式碼
其它常用命令,如下:
# 列出env列表 workon # 進入指定的env workon name # 退出當前env deactivate # 刪除env rmvirtualenv name 複製程式碼
ok,我們使用pip安裝virtualenv和virtualenvwrapper,順利的解決了不同版本的python問題,可以愉快的開發(玩耍)了。