可是稍微了解了一下后發(fā)現(xiàn)其實 Python 不止能當腳本語言來用?;谝欢ǖ墓ぞ哝湥琍ython 也能寫出漂亮標準的項目代碼、將環(huán)境和依賴管理的明明白白。
#?基于PIP
最基礎(chǔ)的依賴管理應(yīng)當能解決如下問題:
-
能快速配置好項目依賴,搭建好開發(fā)環(huán)境。
-
明確知道當前項目依賴了哪些第三方的包,以及他們的依賴樹。
-
能快速添加和移除給定的依賴,進行依賴調(diào)解。
這些功能使用 Pip 工具鏈其實是能很方便做到的。
?快速配置環(huán)境(pip)
想簡單預(yù)覽當前環(huán)境下的依賴包可以直接用?pip list
?命令:
$?pip?list
Package????Version
----------?-------------------
certifi????2020.6.20
pip????????19.3.1
setuptools?44.0.0.post20200106
wheel??????0.36.2
對于一個空的 Python 環(huán)境,基礎(chǔ)一般只會有這四個包。我們這樣就知道了當前環(huán)境中有哪些包,以及他們的版本。
為了方便說明,我們先多引一些依賴?pip install flask
?。
$?pip?list
Package??????Version
------------?-------------------
certifi??????2020.6.20
click????????7.1.2
Flask????????1.1.2
itsdangerous?1.1.0
Jinja2???????2.11.3
MarkupSafe???1.1.1
pip??????????19.3.1
setuptools???44.0.0.post20200106
Werkzeug?????1.0.1
wheel????????0.36.2
安裝了 Flask 之后,我們發(fā)現(xiàn)除了 Flask 他還多引入了好多個間接依賴。
如果想要將這個信息記錄下來,我們可以用?pip freeze
?命令,記在 requirements.txt 中(一個約定俗成的名字)。
$?pip?freeze?>?requirements.txt
$?cat?requirements.txt
certifi==2020.6.20
click==7.1.2
Flask==1.1.2
itsdangerous==1.1.0
Jinja2==2.11.3
MarkupSafe==1.1.1
Werkzeug==1.0.1
好了,記下這個文件,以后我們?nèi)绻枰谝粋€新的 Python 環(huán)境中引入當前的依賴,只需要使用?pip install -r requirements.txt
?即可。
?明確項目依賴(pipdeptree)
pip list
?或?pip freeze
?打印出來的依賴有一個問題,就是并沒有明確依賴關(guān)系。這樣的壞處是,當我們想清理依賴的時候,就不知道到底哪些依賴是能被直接刪除的、哪些依賴又是被間接依賴而不能輕易刪除的。
例如我們可能在項目中用了 Flask ,但是我們可能不知道 Flask 也引用了 Jinja2 。這是我們?nèi)绻米詣h除了 Jinja2 ,項目就可能跑不起來。。。
這時就可以使用?pipdeptree?工具來管理依賴樹:
$?pip?install?pipdeptree
...
$?pipdeptree
certifi==2020.6.20
Flask==1.1.2
??-?click?[required:?>=5.1,?installed:?7.1.2]
??-?itsdangerous?[required:?>=0.24,?installed:?1.1.0]
??-?Jinja2?[required:?>=2.10.1,?installed:?2.11.3]
????-?MarkupSafe?[required:?>=0.23,?installed:?1.1.1]
??-?Werkzeug?[required:?>=0.15,?installed:?1.0.1]
pipdeptree==2.0.0
??-?pip?[required:?>=6.0.0,?installed:?19.3.1]
setuptools==44.0.0.post20200106
wheel==0.36.2
現(xiàn)在我們就知道了,原來 Jinja2 是被 Flask 依賴的,這樣我們就不會隨便刪除了。。。
?項目依賴治理(pip-autoremove)
那么問題來了,如果我忽然不想依賴 Flask 了,我們需要怎么做呢?
無腦的做法是?pip uninstall flask -y
?。不那么顯然的是,這其實不夠優(yōu)雅:
$?pip?uninstall?flask?-y
...
$?pipdeptree
certifi==2020.6.20
click==7.1.2
itsdangerous==1.1.0
Jinja2==2.11.3
??-?MarkupSafe?[required:?>=0.23,?installed:?1.1.1]
pipdeptree==2.0.0
??-?pip?[required:?>=6.0.0,?installed:?19.3.1]
setuptools==44.0.0.post20200106
Werkzeug==1.0.1
wheel==0.36.2
發(fā)現(xiàn)沒,F(xiàn)lask 雖然被卸載了,但是他的依賴包并沒有卸載干凈。你可能需要重新一個一個判斷你是否需要剩下的包,然后再遞歸刪除。。。
幸運的是,我們就可以用?pip-autoremove?工具來做這件事。我們重新安裝Flask,再用這個工具刪除試試:
$?pip?install?flask
$?pip?install?pip-autoremove
$?pip-autoremove?flask?-y
$?pipdeptree
certifi==2020.6.20
pip-autoremove==0.9.1
pipdeptree==2.0.0
??-?pip?[required:?>=6.0.0,?installed:?19.3.1]
setuptools==44.0.0.post20200106
wheel==0.36.2
這下干凈了。
#?基于Conda
pip 能基本解決單一項目的環(huán)境處理問題。但是由于 Python 是全局環(huán)境,如果有多個項目,我們就無法區(qū)分項目維度的依賴。解決這個問題一般有兩個思路,一個是像 Node.js 一樣用 package.json 配置文件支持項目維度的環(huán)境隔離,另一個就是走 rvm、nvm的思路用虛擬環(huán)境隔離。目前看 Python 只能支持后者,也就是用基于 Conda 的虛擬環(huán)境。
值得一提的是,conda 雖然為Python 而生,但他其實是一個通用的虛擬環(huán)境工具。他的官網(wǎng)寫的很清楚:
Package, dependency and environment management for any language---Python, R, Ruby, Lua, Scala, Java, JavaScript, C/ C++, FORTRAN
Conda is an open-source package management system and environment management system that runs on Windows, macOS, and Linux. Conda quickly installs, runs, and updates packages and their dependencies. Conda easily creates, saves, loads, and switches between environments on your local computer. It was created for Python programs but it can package and distribute software for any language.
很強大,有多強大,可以將不同語言的依賴環(huán)境整合在一起的強大。
?安裝
Conda 官網(wǎng)給了兩個發(fā)行版本,一個是 Anaconda ,一個是 Miniconda。Anaconda 相比 Miniconda 主要是多預(yù)裝了很多科學計算的庫,而我更喜歡按需使用不喜歡全家桶,所以我選 Miniconda。
官網(wǎng)下載miniconda3,并執(zhí)行安裝腳本。
安裝后會發(fā)現(xiàn) .bashrc 下多了幾行:
#?>>>?conda?initialize?>>>
#?!!?Contents?within?this?block?are?managed?by?'conda?init'?!!
__conda_setup="$('/home/zhenping/miniconda3/bin/conda'?'shell.bash'?'hook'?2>?/dev/null)"
if?[?$??-eq?0?];?then
????eval?"$__conda_setup"
else
????if?[?-f?"/home/zhenping/miniconda3/etc/profile.d/conda.sh"?];?then
????????.?"/home/zhenping/miniconda3/etc/profile.d/conda.sh"
????else
????????export?PATH="/home/zhenping/miniconda3/bin:$PATH"
????fi
fi
unset?__conda_setup
#?<<
重新登錄,或著手動執(zhí)行?source ~/.bashrc
?,以加載conda命令。
現(xiàn)在就會發(fā)現(xiàn)提示符前多了默認環(huán)境 (base),表示當前啟用了默認環(huán)境 base 。
如果不想在會話啟動時就開啟conda環(huán)境,就執(zhí)行?conda config --set auto_activate_base false
?。
?環(huán)境操作
創(chuàng)建一個純凈的 Python2.7 環(huán)境,名字姑且叫 frida ,并激活該環(huán)境。
$?conda?create?-n?frida?python=2.7?-y
...
$?conda?activate?frida
需要注意的是,創(chuàng)建環(huán)境之后,一定要 activate 該環(huán)境,否則后續(xù)的 install 操作還是在 base 環(huán)境。。。
查看已有環(huán)境列表:
(frida)?$?conda?env?list
#?conda?environments:
#
base?????????????????????/home/myths/miniconda3
frida?????????????????*??/home/myths/miniconda3/envs/frida
查看當前環(huán)境下的依賴:
(frida)?$?conda?list
#?packages?in?environment?at?/home/myths/miniconda3/envs/frida:
#
#?Name????????????????????Version???????????????????Build??Channel
_libgcc_mutex?????????????0.1????????????????????????main
ca-certificates???????????2021.4.13????????????h06a4308_1
certifi???????????????????2020.6.20??????????pyhd3eb1b0_3
libffi????????????????????3.3??????????????????he6710b0_2
libgcc-ng?????????????????9.1.0????????????????hdf63c60_0
libstdcxx-ng??????????????9.1.0????????????????hdf63c60_0
ncurses???????????????????6.2??????????????????he6710b0_1
pip???????????????????????19.3.1???????????????????py27_0
python????????????????????2.7.18???????????????h15b4118_1
readline??????????????????8.1??????????????????h27cfd23_0
setuptools????????????????44.0.0???????????????????py27_0
sqlite????????????????????3.35.4???????????????hdfb4753_0
tk????????????????????????8.6.10???????????????hbc83047_0
wheel?????????????????????0.36.2?????????????pyhd3eb1b0_0
zlib??????????????????????1.2.11???????????????h7b6447c_3
我們發(fā)現(xiàn),與?pip list
?只展示 Python 包不同,conda list
?還展示了對其他語言項目代碼的依賴。
退出環(huán)境:
(frida)?$?conda?deactivate
這里需要注意,conda 的環(huán)境是可以默認嵌套兩層的,因此 deactivate 的時候要看清楚了,可能要 deactivate 兩次才能真正退出 Conda 。
?依賴管理
Conda 也有和?pip freeze
?類似的依賴管理方式:
為當前環(huán)境創(chuàng)建配置文件:
(frida)?$?conda?env?export?>?environment.yaml
(frida)?$?cat?environment.yaml
name:?frida
channels:
??-?defaults
dependencies:
??-?_libgcc_mutex=0.1=main
??-?ca-certificates=2021.4.13=h06a4308_1
??-?certifi=2020.6.20=pyhd3eb1b0_3
??-?libffi=3.3=he6710b0_2
??-?libgcc-ng=9.1.0=hdf63c60_0
??-?libstdcxx-ng=9.1.0=hdf63c60_0
??-?ncurses=6.2=he6710b0_1
??-?pip=19.3.1=py27_0
??-?python=2.7.18=h15b4118_1
??-?readline=8.1=h27cfd23_0
??-?setuptools=44.0.0=py27_0
??-?sqlite=3.35.4=hdfb4753_0
??-?tk=8.6.10=hbc83047_0
??-?wheel=0.36.2=pyhd3eb1b0_0
??-?zlib=1.2.11=h7b6447c_3
prefix:?/home/myths/miniconda3/envs/frida
根據(jù)配置文件復(fù)現(xiàn)當前環(huán)境:
$?conda?env?create?-f?environment.yaml
?IDE集成
使用 conda 還有個很大的好處就是和 IDE 可以非常方便的集成。
#?一些思考
用Conda做其他語言的虛擬環(huán)境方便么?
現(xiàn)在看起來非常方便,幾乎所有需要區(qū)分全局環(huán)境的地方都可以用。比如 Java 環(huán)境:
$?conda?create?-n?java8
$?conda?activate?java8
$?conda?install?openjdk=8.0.152?-y
$?conda?list
#?packages?in?environment?at?/home/myths/miniconda3/envs/java8:
#
#?Name????????????????????Version???????????????????Build??Channel
openjdk???????????????????8.0.152??????????????h7b6447c_3
同時,我們也可以在這個環(huán)境中集成 Node 環(huán)境,Python 環(huán)境,Ruby環(huán)境,甚至集成一些 curl、wget 等常用命令,非常方便。這對于一些跨語言、跨環(huán)境項目的環(huán)境搭建可是太有幫助了。。。
如何找conda支持的包呢?
可以直接用?conda search xxx
?來搜索。不過這樣可能不太全,我們也可以在 https://anaconda.org/search?q=openjdk 這里根據(jù)關(guān)鍵字搜索,當然也可以向這里貢獻。
安裝 Python 包是用 conda 好還是用 pip 好?
如果明確是純粹的 python 包,還是建議用 pip install 安裝,方便用 pip 統(tǒng)一管理。對于跨語言的、或者是本身就整合了各種依賴的環(huán)境(比如 tenserflow),再考慮用 conda install。
審核編輯:湯梓紅
評論
查看更多