關於我
一個有思想的程序猿,終身學習實踐者,目前在一個創業團隊任team lead,技術棧涉及Android、Python、Java和Go,這個也是咱們團隊的主要技術棧。
Github:https://github.com/hylinux1024
微信公衆號:終身開發者(angrycode)html
Python
擁有大量的第三方庫,引用這些庫也很是方便,經過pip install
就能夠將這些第三方庫安裝到本地Python
庫文件目錄中,而後就能夠import
到項目中,極大地提高了開發者的編碼效率。
但這也帶來了一個問題:當A
項目和B
項目同時引用Lib
庫,而A
項目須要Lib
版本是1.0,B
項目須要Lib
的版本是2.0。這樣在使用pip install
命令將Lib
直接安裝到本地全局環境中就會發生衝突,有可能會致使A
和B
的運行環境沒法同時獲得知足而運行失敗。python
因而虛擬環境(virtualenv
)就出現了。它的核心思想就是爲每一個項目提供獨立的運行環境,這樣不一樣的項目依賴庫就不會衝突。linux
安裝虛擬環境也很是簡單,可使用venv
模塊,例如在項目目錄中使用Python3
建立一個虛擬環境git
➜ python3 -m venv venv
因而在項目目錄中就多了一個venv
的文件目錄。這個目錄就是該項目的虛擬環境。github
要使用虛擬環境就必須激活shell
➜ source venv/bin/activate
而後在命令行中就會出現flask
(venv) ➜
說明虛擬環境已經激活。微信
要取消虛擬環境,使用ide
(venv) ➜ deactivate
激活虛擬環境後就可使用pip
命令安裝項目的依賴庫。例如工具
(venv) ➜ pip install requests
pip
會將requests
安裝到venv/lib/python3.7/site-packages
目錄中。
要卸載依賴庫
(venv) ➜ pip uninstall requests
要查看venv
中安裝了哪些依賴庫
(venv) ➜ pip list Package Version -------------- -------- beautifulsoup4 4.7.1 certifi 2019.3.9 requests 2.21.0
使用pip freeze
能夠將依賴庫列表保存到一個requirements.txt
文件,可讓其餘項目的協做者能夠快速地創建項目的運行環境。
(venv) ➜ pip freeze > requirements.txt
因而要安裝項目依賴
(venv) ➜ pip install -r requirements.txt
這樣就能夠創建一個統一的運行環境了。
到目前爲止一切都運行良好,這應該是不錯的解決方案了吧。實際上這種方案我一直都在使用,目前也是,也並無遇到什麼問題。
直到有一天有人說使用venv+pip
也不能保證個人運行環境的一致性和可靠性。
他的理由也很簡單,項目的庫環境是依賴requirements.txt
,而requirements.txt
中庫有沒有指定版本號,這樣在使用pip install -r requirements.txt
的時候也會致使安裝不肯定的版本。
例如
beautifulsoup4 certifi requests
固然能夠爲每一個庫指定確切的版號來解決,因而
beautifulsoup4 4.7.1 certifi 2019.3.9 requests 2.21.0
這樣作能夠解決上面的問題,可是若是某個第三方庫修補了一個漏洞,要使用pip install --upgrade
更新這些依賴庫的話,就不是那麼容易了。
還有一個問題requirements.txt
中的依賴庫也有可能會出現版本號衝突。 狀況是這樣:
ALib -> sublib_1.0 BLib -> sublib_2.1
ALib
和BLib
同時依賴於sublib
,但它們依賴的版本不同,最終在使用pip install -r requirements.txt
也可能會由於依賴庫中的子依賴庫版本不兼容而致使項目運行失敗。
因而就出現了pipenv
說實話在這以前我一直都是使用venv+pip
,當看到上面的問題以後,我以爲有必要了解一下pipenv
。
pipenv
➜ pip install pipenv
一旦安裝完成就會引用兩個文件,Pipfile
和Pipfile.lock
。前者是用於取代requirements.txt
文件的,後者則是用於保證依賴庫的肯定性和一致性。
實際上,pipenv
命令底層也是封裝了pip
和venv
的操做,並提供了一套簡單的交互命令。
建立虛擬環境
要在項目目錄下(如pipenvdemo
)使用
➜ pipenv shell
當出現相似如下信息時說明虛擬環境建立並激活成功,固然還可使用--two
或--three
參數指定使用Python2
仍是Python3
來建立,也可使用肯定的Python
版本號如--python3.7
➜ pipenv shell --three ➜ pipenv shell --python3.7
因爲我電腦本地Python
環境是3.7,因此這裏直接默認它會指向本地默認版本
Creating a virtualenv for this project… Pipfile: /Users/mac/PycharmProjects/pipenvdemo/Pipfile Using /usr/local/opt/python/bin/python3.7 (3.7.3) to create virtualenv… ⠋ Creating virtual environment...Already using interpreter /usr/local/opt/python/bin/python3.7 Using base prefix '/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7' New python executable in /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/python3.7 Also creating executable in /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/python Installing setuptools, pip, wheel... done. ✔ Successfully created virtual environment! Virtualenv location: /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9 Creating a Pipfile for this project… Launching subshell in virtual environment… . /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9/bin/activate
同時在項目目錄下(如pipenvdemo
)生成一個Pipfile
文件。相似的,命令行也會出現如下樣式
(pipenvdemo) ➜ pipenvdemo
其中Pipfile
的內容爲
[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] [packages] [requires] python_version = "3.7"
當要安裝第三方庫當時候就直接使用pipenv install
命令,如下指定flask
版本號進行安裝。
➜ pipenv install flask==1.0.1
也能夠不指定版本號
➜ pipenv install flask
終端會出現相似如下信息
Installing flask==1.0.1… Adding flask to Pipfile's [packages]… ✔ Installation Succeeded Pipfile.lock not found, creating… Locking [dev-packages] dependencies… Locking [packages] dependencies… ⠙ Locking...
還可使用--dev
參數用於安裝開發環境依賴的庫
➜ pipenv install pytest --dev
在項目目錄又生成了另外一文件Pipfile.lock
,而且Pipfile
文件也會更新
[[source]] name = "pypi" url = "https://pypi.org/simple" verify_ssl = true [dev-packages] pytest = "*" [packages] flask = "==1.0.1" [requires] python_version = "3.7"
看到在[packages]
標籤下列出了依賴庫flask
和版本號,上面還有一個[dev-packages]
是用於標示開發版本依賴庫,這樣能夠用於區分生產環境和開發環境。只有在命令中使用了--dev
參數纔會安裝[dev-packages]
下列出的依賴庫。
Pipfile.lock
文件的內容要豐富一些,主要是包含了依賴庫(包括子依賴庫)的版本號以及文件hash
的信息,從而能夠保證依賴庫是肯定的。
{ "_meta": { "hash": { "sha256": "3bba1f1c4de8dd6f8d132dda17cd3c720372a1eed94b9523b9c23013e951c8ae" }, "pipfile-spec": 6, "requires": { "python_version": "3.7" }, "sources": [ { "name": "pypi", "url": "https://pypi.org/simple", "verify_ssl": true } ] }, "default": { "click": { "hashes": [ "sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13", "sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7" ], "version": "==7.0" }, "flask": { "hashes": [ "sha256:cfc15b45622f9cfee6b5803723070fd0f489b3bd662179195e702cb95fd924c8", "sha256:dbe2a9f539f4d0fe26fa44c08d6e556e2a4a4dd3a3fb0550f39954cf57571363" ], "index": "pypi", "version": "==1.0.1" }, "itsdangerous": { "hashes": [ "sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19", "sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749" ], "version": "==1.1.0" }, "jinja2": { "hashes": [ "sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013", "sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b" ], "version": "==2.10.1" }, "markupsafe": { "hashes": [ "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473", "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161", "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235", "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5", "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff", "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b", "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1", "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e", "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183", "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66", "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1", "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1", "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e", "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b", "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905", "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735", "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d", "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e", "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d", "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c", "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21", "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2", "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5", "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b", "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6", "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f", "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f", "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7" ], "version": "==1.1.1" }, "werkzeug": { "hashes": [ "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c", "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6" ], "version": "==0.15.4" } }, "develop": {} }
假設咱們要把項目發佈到生產環境了,這時就要使用pipenv lock
命令
➜ pipenv lock
終端會出現相似以下信息
Locking [dev-packages] dependencies… ✔ Success! Locking [packages] dependencies…
這個命令會建立或更新Pipfile.lock
文件,須要注意的是咱們不該該手動修改此文件。
而後就能夠在生產環境中使用如下命令恢復環境
➜ pipenv install --ignore-pipfile
指定--ignore-pipfile
參數的意思是,只要恢復Pipfile.lock
的列表的依賴庫和子依賴庫。若是要恢復開發環境中的依賴庫,即安裝[dev-packages]
下面的依賴庫,可使用
➜ pipenv install --dev
以上就是pipenv
的簡單用法。
如今再來看看前面提到的問題
ALib -> sublib_1.0 BLib -> sublib_2.1
A
和B
模塊都依賴同一個庫,但依賴庫的版本號不同。這時使用pipenv install
就出現相似如下信息
Warning: Your dependencies could not be resolved. You likely have a mismatch in your sub-dependencies. You can use $ pipenv install --skip-lock to bypass this mechanism, then run $ pipenv graph to inspect the situation. Could not find a version that matches sublib=1.0,sublib=2.1
可使用
➜ pipenv graph
查看當前項目依賴庫及其子依賴庫信息,以樹層級方式進行展現
Flask==1.0.1 - click [required: >=5.1, installed: 7.0] - itsdangerous [required: >=0.24, installed: 1.1.0] - Jinja2 [required: >=2.10, installed: 2.10.1] - MarkupSafe [required: >=0.23, installed: 1.1.1] - Werkzeug [required: >=0.14, installed: 0.15.4] pytest==4.6.2 - atomicwrites [required: >=1.0, installed: 1.3.0] - attrs [required: >=17.4.0, installed: 19.1.0] - importlib-metadata [required: >=0.12, installed: 0.17] - zipp [required: >=0.5, installed: 0.5.1] - more-itertools [required: >=4.0.0, installed: 7.0.0] - packaging [required: Any, installed: 19.0] - pyparsing [required: >=2.0.2, installed: 2.4.0] - six [required: Any, installed: 1.12.0] - pluggy [required: >=0.12,<1.0, installed: 0.12.0] - importlib-metadata [required: >=0.12, installed: 0.17] - zipp [required: >=0.5, installed: 0.5.1] - py [required: >=1.5.0, installed: 1.8.0] - six [required: >=1.10.0, installed: 1.12.0] - wcwidth [required: Any, installed: 0.1.7]
本例中咱們安裝了flask
和pytest
,pipenv graph
命令展現了它們各自須要的依賴。還能夠加上--reverse
參數
➜ pipenv graph --reverse
使用這個參數能夠很方便的分析出衝突的庫。
atomicwrites==1.3.0 - pytest==4.6.2 [requires: atomicwrites>=1.0] attrs==19.1.0 - pytest==4.6.2 [requires: attrs>=17.4.0] click==7.0 - Flask==1.0.1 [requires: click>=5.1] itsdangerous==1.1.0 - Flask==1.0.1 [requires: itsdangerous>=0.24] MarkupSafe==1.1.1 - Jinja2==2.10.1 [requires: MarkupSafe>=0.23] - Flask==1.0.1 [requires: Jinja2>=2.10] more-itertools==7.0.0 - pytest==4.6.2 [requires: more-itertools>=4.0.0] pip==19.1.1 py==1.8.0 - pytest==4.6.2 [requires: py>=1.5.0] pyparsing==2.4.0 - packaging==19.0 [requires: pyparsing>=2.0.2] - pytest==4.6.2 [requires: packaging] setuptools==41.0.1 six==1.12.0 - packaging==19.0 [requires: six] - pytest==4.6.2 [requires: packaging] - pytest==4.6.2 [requires: six>=1.10.0] wcwidth==0.1.7 - pytest==4.6.2 [requires: wcwidth] Werkzeug==0.15.4 - Flask==1.0.1 [requires: Werkzeug>=0.14] wheel==0.33.4 zipp==0.5.1 - importlib-metadata==0.17 [requires: zipp>=0.5] - pluggy==0.12.0 [requires: importlib-metadata>=0.12] - pytest==4.6.2 [requires: pluggy>=0.12,<1.0] - pytest==4.6.2 [requires: importlib-metadata>=0.12]
刪除一個依賴包
➜ pipenv uninstall numpy
刪除全部依賴庫
➜ pipenv uninstall --all ➜ pipenv uninstall --all-dev
--all-dev
是指定刪除全部開發環境的依賴。
查看venv
目錄路徑
➜ pipenv --venv /Users/mac/.local/share/virtualenvs/pipenvdemo-fHPp2Wq9
查看當前項目路徑
➜ pipenv --where /Users/mac/PycharmProjects/pipenvdemo
從目前使用pip+venv
的包管理工具遇到的問題出發,提到這種方式遇到的問題是依賴庫以及它們的子依賴庫又可能會出現版本衝突以及管理的問題。因而有人提出新的包管理工具pipenv
。它有兩個核心文件Pipfile
和Pipfile.lock
文件,前者用於指定當前項目中的直接依賴庫信息,然後者則指定了依賴的依賴的庫信息,經過依賴的hash
值以及版本號來肯定依賴庫的一致性。