新聞中心
大家好!我是虎哥。

創(chuàng)新互聯(lián)建站主要從事成都做網(wǎng)站、成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)策勒,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):13518219792
之前一直比較抵觸用 Python ,很大一部分原因是覺得 Python 項(xiàng)目的環(huán)境管理比較混亂。Node.js 有 Npm 包管理工具,通過 package.json 配置項(xiàng)目依賴,最多再通過 nvm 來進(jìn)行環(huán)境切換;Java 有 Maven Gradle 來進(jìn)行包管理和項(xiàng)目依賴配置,并體現(xiàn)在 pom.xml 和 build.gradle 等中。
而 Python 相比編程語(yǔ)言有時(shí)更體現(xiàn)了腳本語(yǔ)言的特性,系統(tǒng)化和標(biāo)準(zhǔn)化程度都不太高。很多 Python 項(xiàng)目上來就是懟代碼,沒有聲明依賴、配置環(huán)境的文件。
這樣的好處是簡(jiǎn)單項(xiàng)目堆砌起來非???,但是一旦代碼量上了規(guī)模,依賴管理、環(huán)境配置、項(xiàng)目啟動(dòng)等就到處都是坑。
可是稍微了解了一下后發(fā)現(xiàn)其實(shí) Python 不止能當(dāng)腳本語(yǔ)言來用。基于一定的工具鏈,Python 也能寫出漂亮標(biāo)準(zhǔn)的項(xiàng)目代碼、將環(huán)境和依賴?yán)淼拿髅靼装住?/p>
基于PIP
最基礎(chǔ)的依賴管理應(yīng)當(dāng)能解決如下問題:
- 能快速配置好項(xiàng)目依賴,搭建好開發(fā)環(huán)境。
- 明確知道當(dāng)前項(xiàng)目依賴了哪些第三方的包,以及他們的依賴樹。
- 能快速添加和移除給定的依賴,進(jìn)行依賴調(diào)解。
- 這些功能使用 Pip 工具鏈其實(shí)是能很方便做到的。
快速配置環(huán)境(pip)
想簡(jiǎn)單預(yù)覽當(dāng)前環(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
對(duì)于一個(gè)空的 Python 環(huán)境,基礎(chǔ)一般只會(huì)有這四個(gè)包。我們這樣就知道了當(dāng)前環(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 他還多引入了好多個(gè)間接依賴。
如果想要將這個(gè)信息記錄下來,我們可以用 pip freeze 命令,記在 requirements.txt 中(一個(gè)約定俗成的名字)。
$ 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
好了,記下這個(gè)文件,以后我們?nèi)绻枰谝粋€(gè)新的 Python 環(huán)境中引入當(dāng)前的依賴,只需要使用 pip install -r requirements.txt 即可。
明確項(xiàng)目依賴(pipdeptree)
pip list 或 pip freeze 打印出來的依賴有一個(gè)問題,就是并沒有明確依賴關(guān)系。這樣的壞處是,當(dāng)我們想清理依賴的時(shí)候,就不知道到底哪些依賴是能被直接刪除的、哪些依賴又是被間接依賴而不能輕易刪除的。
例如我們可能在項(xiàng)目中用了 Flask ,但是我們可能不知道 Flask 也引用了 Jinja2 。這是我們?nèi)绻米詣h除了 Jinja2 ,項(xiàng)目就可能跑不起來。
這時(shí)就可以使用 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 依賴的,這樣我們就不會(huì)隨便刪除了。
項(xiàng)目依賴治理(pip-autoremove)
那么問題來了,如果我忽然不想依賴 Flask 了,我們需要怎么做呢?
無腦的做法是 pip uninstall flask -y 。不那么顯然的是,這其實(shí)不夠優(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 雖然被卸載了,但是他的依賴包并沒有卸載干凈。你可能需要重新一個(gè)一個(gè)判斷你是否需要剩下的包,然后再遞歸刪除。
幸運(yùn)的是,我們就可以用 pip-autoremove 工具來做這件事。我們重新安裝Flask,再用這個(gè)工具刪除試試:
$ 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 能基本解決單一項(xiàng)目的環(huán)境處理問題。但是由于 Python 是全局環(huán)境,如果有多個(gè)項(xiàng)目,我們就無法區(qū)分項(xiàng)目維度的依賴。解決這個(gè)問題一般有兩個(gè)思路,一個(gè)是像 Node.js 一樣用 package.json 配置文件支持項(xiàng)目維度的環(huán)境隔離,另一個(gè)就是走 rvm、nvm的思路用虛擬環(huán)境隔離。目前看 Python 只能支持后者,也就是用基于 Conda 的虛擬環(huán)境。
值得一提的是,conda 雖然為Python 而生,但他其實(shí)是一個(gè)通用的虛擬環(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.
很強(qiáng)大,有多強(qiáng)大,可以將不同語(yǔ)言的依賴環(huán)境整合在一起的強(qiáng)大。
安裝
Conda 官網(wǎng)給了兩個(gè)發(fā)行版本,一個(gè)是 Anaconda ,一個(gè)是 Miniconda。Anaconda 相比 Miniconda 主要是多預(yù)裝了很多科學(xué)計(jì)算的庫(kù),而我更喜歡按需使用不喜歡全家桶,所以我選 Miniconda。
官網(wǎng)下載miniconda3,并執(zhí)行安裝腳本。
安裝后會(huì)發(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
# <<< conda initialize <<<
重新登錄,或著手動(dòng)執(zhí)行 source ~/.bashrc ,以加載conda命令。
現(xiàn)在就會(huì)發(fā)現(xiàn)提示符前多了默認(rèn)環(huán)境 (base),表示當(dāng)前啟用了默認(rèn)環(huán)境 base 。
如果不想在會(huì)話啟動(dòng)時(shí)就開啟conda環(huán)境,就執(zhí)行 conda config --set auto_activate_base false 。
環(huán)境操作
創(chuàng)建一個(gè)純凈的 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
查看當(dāng)前環(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 還展示了對(duì)其他語(yǔ)言項(xiàng)目代碼的依賴。
退出環(huán)境:
(frida) $ conda deactivate
這里需要注意,conda 的環(huán)境是可以默認(rèn)嵌套兩層的,因此 deactivate 的時(shí)候要看清楚了,可能要 deactivate 兩次才能真正退出 Conda 。
依賴管理
Conda 也有和 pip freeze 類似的依賴管理方式:
為當(dāng)前環(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)當(dāng)前環(huán)境:
$ conda env create -f environment.yaml
IDE集成
使用 conda 還有個(gè)很大的好處就是和 IDE 可以非常方便的集成。
一些思考
用Conda做其他語(yǔ)言的虛擬環(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
同時(shí),我們也可以在這個(gè)環(huán)境中集成 Node 環(huán)境,Python 環(huán)境,Ruby環(huán)境,甚至集成一些 curl、wget 等常用命令,非常方便。這對(duì)于一些跨語(yǔ)言、跨環(huán)境項(xiàng)目的環(huán)境搭建可是太有幫助了。
如何找conda支持的包呢?
可以直接用 conda search xxx 來搜索。不過這樣可能不太全,我們也可以在 https://anaconda.org/search?q=openjdk 這里根據(jù)關(guān)鍵字搜索,當(dāng)然也可以向這里貢獻(xiàn)。
安裝 Python 包是用 conda 好還是用 pip 好?
如果明確是純粹的 python 包,還是建議用 pip install 安裝,方便用 pip 統(tǒng)一管理。對(duì)于跨語(yǔ)言的、或者是本身就整合了各種依賴的環(huán)境(比如 tenserflow),再考慮用 conda install。
文章名稱:Python包的依賴管理,有解了!
URL網(wǎng)址:http://fisionsoft.com.cn/article/dpcjddd.html


咨詢
建站咨詢
