如果你寫(xiě)過(guò)不打算打包成庫(kù)的Python項(xiàng)目——比如后端應(yīng)用、REST API、一摞腳本——那你一定被同一個(gè)問(wèn)題反復(fù)折磨:怎么把依賴(lài)裝好,又不讓項(xiàng)目本身被當(dāng)成一個(gè)包安裝?十幾年來(lái),Python社區(qū)都在靠各種“民間偏方”續(xù)命。現(xiàn)在,一個(gè)來(lái)自Sebastian H?ffner的PR #13895,把這一切都終結(jié)了。pip 26.2帶來(lái)了一個(gè)全局標(biāo)志 --only-deps,從此你只要一行命令,就能直接安裝 pyproject.toml 里聲明的全部依賴(lài),而項(xiàng)目本身不會(huì)以任何形式被裝進(jìn)環(huán)境。
這個(gè)改動(dòng)對(duì)很多人來(lái)說(shuō)可能只是“終于有了”,但對(duì)常年跟部署打交道的開(kāi)發(fā)者而言,簡(jiǎn)直是一次遲到的解放。過(guò)去那些揉搓在一塊的 workaround,終于可以?huà)哌M(jìn)歷史的回收站了。要理解這事的治愈程度,得先看看我們這些“可憐的Python靈魂”到底被折磨了多久。
![]()
最早的一招是 requirements.txt + pip freeze。先用 pip freeze 導(dǎo)出當(dāng)前環(huán)境里所有的包和精確版本號(hào),生成一個(gè) requirements.txt,換臺(tái)機(jī)器再 pip install -r requirements.txt。表面上完美,實(shí)則脆弱得像紙糊的:pip freeze 會(huì)連依賴(lài)的依賴(lài)一起導(dǎo)出,而這些依賴(lài)與當(dāng)前的操作系統(tǒng)、Python版本、硬件平臺(tái)深度綁定。換個(gè)環(huán)境,哪怕只是從 macOS 換到 Linux,大量包的版本約束立刻打架,甚至?xí)霈F(xiàn)整個(gè)包找不到的情況。
于是有人把精確版本號(hào)砍掉。十五年前我最古老的記憶之一,就是這樣一條命令:pip freeze --local | grep -v '^\-e' | cut -d = -f 1。把凍結(jié)列表里的 == 和版本號(hào)全剁掉,只留包名。這當(dāng)然粗暴,但起碼換環(huán)境時(shí)不會(huì)因?yàn)榘姹緵_突當(dāng)場(chǎng)去世。后來(lái)很多人演化成了手動(dòng)維護(hù)一個(gè) requirements.txt,只填頂層依賴(lài)的名字,版本號(hào)憑感覺(jué)寫(xiě)。這種操作在當(dāng)時(shí)算得上一種“優(yōu)雅的捷徑”,但本質(zhì)上還是在跟 pip 的局限討價(jià)還價(jià)。
真正的“官道”其實(shí)一直都存在:pip install -e .。這個(gè)命令從 pip 誕生起(2008年)就能正確工作,它會(huì)讀取當(dāng)時(shí)還在 setup.py 里的依賴(lài)列表(后來(lái)遷移到了 pyproject.toml),一股腦給裝好。問(wèn)題就出在那個(gè) -e 上:它是以可編輯模式安裝整個(gè)包。對(duì)于庫(kù)或者需要被其他項(xiàng)目引用的代碼,這很合理。但對(duì)于應(yīng)用后端或者一套 API 框架,你往往有別的啟動(dòng)器或包裝腳本在運(yùn)行 Python 代碼,多出一個(gè)被安裝的包不但多余,還可能在部署里制造各種意外。
![]()
更尷尬的是,pip install -e . 產(chǎn)生的可編輯安裝直到2021年以前還會(huì)生成 egg 分發(fā)文件,這些文件如果不小心維護(hù),會(huì)隨著代碼更新變得陳舊并引發(fā)詭異的導(dǎo)入錯(cuò)誤。可編輯安裝本身也不被推薦用于正式部署,它更適合本地開(kāi)發(fā)。這意味著,一條原本“正確”的命令,在實(shí)際生產(chǎn)中就是不夠干凈。
于是 StackOverflow 上出現(xiàn)了長(zhǎng)達(dá)16年的求助鏈:“pip: Installing only the dependencies”——這條16年前的問(wèn)題下,答案就是教你用 pip install -e .。人們一遍遍提問(wèn),得到的答案卻始終隔靴搔癢。大家都想要一個(gè)不裝包、只裝依賴(lài)的 pip 原生方案,而這個(gè)方案缺席了整整 16 年。
現(xiàn)在,pip 26.2 的 --only-deps 把那個(gè)缺失的零件補(bǔ)上了。以后在項(xiàng)目的 pyproject.toml 里正常聲明依賴(lài),然后在部署腳本或者 Dockerfile 里只需要:pip install --only-deps .。pip 會(huì)解析依賴(lài)、下載、安裝,但根本不會(huì)動(dòng)你的項(xiàng)目代碼本身。沒(méi)有多余的包被注冊(cè)進(jìn)環(huán)境,沒(méi)有 egg 文件的衛(wèi)生問(wèn)題,也不用再為 deployment 專(zhuān)門(mén)維護(hù)一份脫節(jié)的 requirements.txt。
對(duì)個(gè)人開(kāi)發(fā)者來(lái)說(shuō),這簡(jiǎn)化了多年積攢下來(lái)的“手動(dòng)維護(hù)依賴(lài)文件”的壞習(xí)慣;對(duì)團(tuán)隊(duì)和運(yùn)維來(lái)說(shuō),它減少了一整個(gè)容易出錯(cuò)的環(huán)節(jié)。這個(gè)標(biāo)志雖小,卻干凈地解決了一個(gè)橫跨 pip 整個(gè)生命周期的設(shè)計(jì)缺口。那些來(lái)自 16 年前的 StackOverflow 頁(yè)面,現(xiàn)在終于可以歸檔成一段歷史了。
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶(hù)上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.