可是稍微了解了一下后發現其實 Python 不止能當腳本語言來用。基于一定的工具鏈,Python 也能寫出漂亮標準的項目代碼、將環境和依賴管理的明明白白。
#?基于PIP
最基礎的依賴管理應當能解決如下問題:
-
能快速配置好項目依賴,搭建好開發環境。
-
明確知道當前項目依賴了哪些第三方的包,以及他們的依賴樹。
-
能快速添加和移除給定的依賴,進行依賴調解。
這些功能使用 Pip 工具鏈其實是能很方便做到的。
?快速配置環境(pip)
想簡單預覽當前環境下的依賴包可以直接用?pip list
?命令:
$?pip?list
Package????Version
----------?-------------------
certifi????2020.6.20
pip????????19.3.1
setuptools?44.0.0.post20200106
wheel??????0.36.2
對于一個空的 Python 環境,基礎一般只會有這四個包。我們這樣就知道了當前環境中有哪些包,以及他們的版本。
為了方便說明,我們先多引一些依賴?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 之后,我們發現除了 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
好了,記下這個文件,以后我們如果需要在一個新的 Python 環境中引入當前的依賴,只需要使用?pip install -r requirements.txt
?即可。
?明確項目依賴(pipdeptree)
pip list
?或?pip freeze
?打印出來的依賴有一個問題,就是并沒有明確依賴關系。這樣的壞處是,當我們想清理依賴的時候,就不知道到底哪些依賴是能被直接刪除的、哪些依賴又是被間接依賴而不能輕易刪除的。
例如我們可能在項目中用了 Flask ,但是我們可能不知道 Flask 也引用了 Jinja2 。這是我們如果擅自刪除了 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
現在我們就知道了,原來 Jinja2 是被 Flask 依賴的,這樣我們就不會隨便刪除了。。。
?項目依賴治理(pip-autoremove)
那么問題來了,如果我忽然不想依賴 Flask 了,我們需要怎么做呢?
無腦的做法是?pip uninstall flask -y
?。不那么顯然的是,這其實不夠優雅:
$?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
發現沒,Flask 雖然被卸載了,但是他的依賴包并沒有卸載干凈。你可能需要重新一個一個判斷你是否需要剩下的包,然后再遞歸刪除。。。
幸運的是,我們就可以用?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 能基本解決單一項目的環境處理問題。但是由于 Python 是全局環境,如果有多個項目,我們就無法區分項目維度的依賴。解決這個問題一般有兩個思路,一個是像 Node.js 一樣用 package.json 配置文件支持項目維度的環境隔離,另一個就是走 rvm、nvm的思路用虛擬環境隔離。目前看 Python 只能支持后者,也就是用基于 Conda 的虛擬環境。
值得一提的是,conda 雖然為Python 而生,但他其實是一個通用的虛擬環境工具。他的官網寫的很清楚:
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.
很強大,有多強大,可以將不同語言的依賴環境整合在一起的強大。
?安裝
Conda 官網給了兩個發行版本,一個是 Anaconda ,一個是 Miniconda。Anaconda 相比 Miniconda 主要是多預裝了很多科學計算的庫,而我更喜歡按需使用不喜歡全家桶,所以我選 Miniconda。
官網下載miniconda3,并執行安裝腳本。
安裝后會發現 .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
#?<<
重新登錄,或著手動執行?source ~/.bashrc
?,以加載conda命令。
現在就會發現提示符前多了默認環境 (base),表示當前啟用了默認環境 base 。
如果不想在會話啟動時就開啟conda環境,就執行?conda config --set auto_activate_base false
?。
?環境操作
創建一個純凈的 Python2.7 環境,名字姑且叫 frida ,并激活該環境。
$?conda?create?-n?frida?python=2.7?-y
...
$?conda?activate?frida
需要注意的是,創建環境之后,一定要 activate 該環境,否則后續的 install 操作還是在 base 環境。。。
查看已有環境列表:
(frida)?$?conda?env?list
#?conda?environments:
#
base?????????????????????/home/myths/miniconda3
frida?????????????????*??/home/myths/miniconda3/envs/frida
查看當前環境下的依賴:
(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
我們發現,與?pip list
?只展示 Python 包不同,conda list
?還展示了對其他語言項目代碼的依賴。
退出環境:
(frida)?$?conda?deactivate
這里需要注意,conda 的環境是可以默認嵌套兩層的,因此 deactivate 的時候要看清楚了,可能要 deactivate 兩次才能真正退出 Conda 。
?依賴管理
Conda 也有和?pip freeze
?類似的依賴管理方式:
為當前環境創建配置文件:
(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
根據配置文件復現當前環境:
$?conda?env?create?-f?environment.yaml
?IDE集成
使用 conda 還有個很大的好處就是和 IDE 可以非常方便的集成。
#?一些思考
用Conda做其他語言的虛擬環境方便么?
現在看起來非常方便,幾乎所有需要區分全局環境的地方都可以用。比如 Java 環境:
$?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
同時,我們也可以在這個環境中集成 Node 環境,Python 環境,Ruby環境,甚至集成一些 curl、wget 等常用命令,非常方便。這對于一些跨語言、跨環境項目的環境搭建可是太有幫助了。。。
如何找conda支持的包呢?
可以直接用?conda search xxx
?來搜索。不過這樣可能不太全,我們也可以在 https://anaconda.org/search?q=openjdk 這里根據關鍵字搜索,當然也可以向這里貢獻。
安裝 Python 包是用 conda 好還是用 pip 好?
如果明確是純粹的 python 包,還是建議用 pip install 安裝,方便用 pip 統一管理。對于跨語言的、或者是本身就整合了各種依賴的環境(比如 tenserflow),再考慮用 conda install。
審核編輯:湯梓紅
評論
查看更多