8個(gè)建議,為啥不使用Python開發(fā)大型項(xiàng)目!
(點(diǎn)擊上方快速關(guān)注并設(shè)置為星標(biāo),一起學(xué)Python)
來(lái)源:CSDN
整理 | 張仕影? 責(zé)編 | 鄭麗媛
來(lái)源:CSDN
整理 | 張仕影? 責(zé)編 | 鄭麗媛
在開發(fā)者的職業(yè)生涯中,有一個(gè)特定階段,開發(fā)者們會(huì)從為項(xiàng)目做貢獻(xiàn)到掌握自己的技巧。這個(gè)階段對(duì)有些人來(lái)說會(huì)來(lái)得早一些,有些則也會(huì)晚一些,而另一部分人則無(wú)法到達(dá)這個(gè)階段。
不過,大多數(shù)職業(yè)生涯較長(zhǎng)的開發(fā)人員都經(jīng)歷過這個(gè)階段。我將這稱之為自己構(gòu)建的點(diǎn)。
如果你已經(jīng)到達(dá)了那個(gè)階段,你面對(duì)的第一個(gè)問題是:它是如何運(yùn)作的?用戶體驗(yàn)如何?架構(gòu)是怎樣的?數(shù)據(jù)如何流動(dòng)?以及很多類似這樣的問題。
我在這里就不為你回答這些這些問題的答案了。無(wú)論你開始哪一個(gè)項(xiàng)目,它們都需要根據(jù)項(xiàng)目來(lái)高度定制,并且每一個(gè)都應(yīng)該至少有一篇獨(dú)立的文章來(lái)解答。
不過,我想回答其中一個(gè)問題:哪種語(yǔ)言最適合這個(gè)項(xiàng)目?
你可能認(rèn)為這取決于項(xiàng)目的類型,的確,但是每種編程語(yǔ)言都有一些缺陷。實(shí)際上,Python 也有很多缺陷,尤其是當(dāng)你試圖用它來(lái)構(gòu)建一個(gè)大型程序的時(shí)候。
1、變量聲明不存在,這是一個(gè)問題
Python 之禪表明:顯式優(yōu)于隱式。但當(dāng)涉及到變量聲明時(shí),Python 中的隱式比顯式更常見。(注:Python 之禪指的是 Tim Peters 編寫的關(guān)于 python 編程準(zhǔn)則。)
我們先來(lái)看看下面這一小段的 C 代碼:
char notpython[50] = "This isn't Python.";在對(duì)比 Python 之前,我們先來(lái)深入研究以下這個(gè)問題。
“char” 是一個(gè)類型標(biāo)識(shí)符,表示之后的所有內(nèi)容都與一個(gè)字符串有關(guān)。“notpython” 是我給這個(gè)字符串取的名字。[50] 表示C將為此保留50個(gè)字符的內(nèi)存空間。不過,在本例中,我可以使用 19個(gè) 字符——每個(gè)字符一個(gè),在末尾加上一個(gè)空字符\0,最后用一個(gè)分號(hào)巧妙地結(jié)束。
這種顯式聲明在 C 語(yǔ)言中是強(qiáng)制性的。如果你忽略它,編譯器則會(huì)罷工。
這種方式起初看起來(lái)既愚蠢又乏味,但是它的回報(bào)非常大。
兩周或兩年后讀 C 代碼的你突然發(fā)現(xiàn)了一個(gè)你不知道的變量,那么查一下聲明就可以。如果你給它起了一個(gè)有意義的名字,那這就會(huì)給你一個(gè)極大的提示:它是什么,它在做什么,以及哪里需要它。
對(duì)比一下 Python,你幾乎可以隨時(shí)創(chuàng)造變量。但如果你沒有給它取一個(gè)有意義的名字,或者至少留下一個(gè)關(guān)于它的注釋,那么將來(lái)可能會(huì)一團(tuán)糟。
在 Python 中,除了深入研究代碼,否則很難理解變量在做什么。甚至如果你在變量中有一個(gè)拼寫錯(cuò)誤,你可能會(huì)破壞整個(gè)代碼——Python 并沒有像 C 語(yǔ)言那樣的保護(hù)聲明。
如果你要處理的是較小的項(xiàng)目,或者不是很復(fù)雜的項(xiàng)目,比如說幾千行代碼,這就沒有什么問題 ,但如果是更大的項(xiàng)目…那就糟糕了。
你可以在 Python 中做顯式變量聲明,但只有一些非常勤奮的程序員才會(huì)這么做。當(dāng)編譯器沒有問題時(shí),很多程序員們往往會(huì)忘記這些額外的代碼行。
編寫 Python 是很快的,對(duì)于一些小而簡(jiǎn)單的項(xiàng)目來(lái)說,閱讀 Python 也是很快的。不過閱讀和維護(hù)大型 Python 項(xiàng)目時(shí),你最好成為找描述性變量名和注釋所有代碼的世界英雄,否則你就完了。
2、模塊,你屬于哪里?
如果你認(rèn)為事情不會(huì)變得更糟糕,那么你就錯(cuò)了。
變量從哪里開始“存在”于代碼中的問題不僅僅來(lái)自隱式聲明,還可能來(lái)自其他模塊,它們通常是以 my_module.my_variable() 這樣的形式存在。如果你被這樣一個(gè)變量搞糊涂了,那么當(dāng)你檢查它出現(xiàn)在主文件中的其他位置時(shí),你依舊會(huì)感到困惑。
你還必須檢查代碼中是否包含以下兩行代碼之一:
import my_modulefrom another_module import my_module
第二行的作用是告訴編譯器,你需要從一個(gè)包含更多內(nèi)容的模塊中獲得某個(gè)函數(shù)或變量。
這很煩人,因?yàn)橛心K比你在 PyPI 上找到的更多,還可以在計(jì)算機(jī)上導(dǎo)入任何其他 Python 文件。所以快速搜索你的函數(shù)和變量并非全然有益,甚至它可能會(huì)變得更糟糕。
模塊可以依賴于其他模塊。因此如果你不走運(yùn),你導(dǎo)入了模塊 A、 B 和 C,但是這些模塊依賴于模塊 E、 F 、G 和 H,而模塊 E、 F、G 和 H 又依賴于模塊 I、 J 和 K。突然之間,你需要管理的不僅是 3 個(gè)模塊,而是 10 個(gè)模塊。
更糟糕的是,有時(shí)候并不是這么簡(jiǎn)單的結(jié)構(gòu)。比如說模塊 B 和 C 也取決于模塊 M 和 N ,而 J 也依賴于 M、C 和 H 依賴于 Q…后面不必多說,你懂的。
這是一個(gè)迷宮,也是一個(gè)由 Pythonians 創(chuàng)造且真實(shí)存在的依賴地獄。
循環(huán)依賴是迷宮中最丑陋的野獸。如果模塊 A 依賴于模塊 B,但模塊 B 同時(shí)使用模塊 A 的一部分…
在小項(xiàng)目中這并不是問題,但在大項(xiàng)目中……歡迎來(lái)到叢林。
3、大量依賴沖突
我要抱怨的不僅僅是模塊本身,還有它們的版本。
原則上, Python 有活躍的用戶群,很多模塊也會(huì)定期更新,這是非常好的。只是有一個(gè)問題:并非所有版本的模塊都能與其他模塊始終保持兼容。
比如說你使用模塊 A 和 B,而兩者都依賴于模塊 C。但是 A 需要3.2或者更高版本的 C, B 需要2.9或者更早的版本 C。
可你不在乎模塊 C,你只想要 A 和 B。
世界上沒有任何工具可以幫助你解決這場(chǎng)沖突。幸運(yùn)的話,你會(huì)找到一個(gè)和你遇到同樣問題的人寫的補(bǔ)丁。如果你不是那么幸運(yùn),你將不得不編寫補(bǔ)丁。或者你用別的包。再或者,你可以重寫其中一個(gè)包(A 或者 B),然后在需要 C 的地方找到變通方法。
無(wú)論如何,你都需要額外的時(shí)間來(lái)解決問題。這就像在一個(gè)叢林里,你需要耐心以及一些導(dǎo)航工具來(lái)讓自己找到出路。
拋開依賴沖突,也有一些不錯(cuò)的工具。像“pip”,它就可以很容易地安裝軟件包。使用一個(gè)簡(jiǎn)單的“requirements . txt”,你可以指定哪些包以及你希望使用哪些版本等等。虛擬環(huán)境將所有包放在一個(gè)地方,并與主要 Python 分開安裝。
對(duì)于更大更復(fù)雜的項(xiàng)目,還有“conda”、 YAML 文件等等。但是你需要學(xué)習(xí)如何使用每一種工具,確保用最少的時(shí)間解決問題。
4、不同的機(jī)器,不同的 Python
即使你已經(jīng)解決了機(jī)器上的所有依賴問題,你的 Python 運(yùn)行起來(lái)十分流暢,也不能保證它在其他機(jī)器上運(yùn)行時(shí)依舊這么流暢。像“pip”、“ requirements . txt ”這樣的工具和虛擬環(huán)境可以幫助你瀏覽輕度依賴地獄,但僅限于本地。
在每臺(tái)新機(jī)器上,你都需要檢查并重新安裝各個(gè)版本及要求。
唯一簡(jiǎn)便的解決方案是 Jupyter notebooks。在 Jupyter notebooks 中你可以用任何你喜歡的版本寫東西。在 Jupyter 中,一切都運(yùn)行在一個(gè)在線服務(wù)器上,你可以將這些文件發(fā)送給任何人,他們同樣能夠使用它們。
不過這也有一個(gè)明顯的缺點(diǎn):Jupyter 筆記本只有圖形界面。但是使用圖形界面,處理具有許多相互關(guān)聯(lián)文件的大型項(xiàng)目是相當(dāng)困難的。
也許這就是為什么我很難在 Jupyter 筆記本上看到大項(xiàng)目的原因吧。
而其他語(yǔ)言只要有虛擬機(jī),問題就解決了。
5、pip 之外的世界
假設(shè)你已經(jīng)設(shè)法通過使用 Jython 或 PyPy 或其他解決方案,將你的項(xiàng)目移植到不同的機(jī)器上(雖然這些比虛擬機(jī)處理起來(lái)要笨拙一些,但至少能奏效),接下來(lái)為了整合大型項(xiàng)目,你可能會(huì)集成 C 包、 Fortran 包等。這樣做有許多好處:C包可能不存在于 Python 中,而且通常更快。由于遺留原因,科學(xué)包往往只存在于 Fortran 中。
但實(shí)際上,在這過程中你必須使用像 ‘gcc’、‘gfortran’ 這樣的編譯器,甚至其它更多編譯器——這很麻煩,因?yàn)樵?Python 代碼中集成 C 模塊的文檔超過 4500 字,集成 Fortran 的文檔也不短。
所以如果一開始就用 C 構(gòu)建整個(gè)項(xiàng)目可能會(huì)更好:雖然要慢一些,但是你可以避免必須使用多個(gè)編譯器和接口的情況。
C 很古老,幾乎任何東西都有包,甚至還有用戶友好的機(jī)器學(xué)習(xí)軟件包。
6、使用全局解釋器鎖鎖定性能
全局解釋器鎖(GIL),從 Python 誕生的第一天起就已經(jīng)存在,它使終端用戶的存儲(chǔ)管理變得非常容易。
至少在較小的項(xiàng)目中,開發(fā)人員在使用 Python 時(shí)根本不需要考慮計(jì)算機(jī)內(nèi)存。相比之下,在C中每個(gè)變量都保留了內(nèi)存位!
基本上,GIL 會(huì)計(jì)算一個(gè)變量在代碼中每個(gè)部分被引用了多少次。如果不再需要該變量,則會(huì)釋放它所占用的內(nèi)存空間。因此在小型項(xiàng)目中,GIL 有助于提高性能,因?yàn)椴槐匾膬?nèi)存空間被清除掉了。但是在大項(xiàng)目中有一個(gè)問題:GIL 不喜歡多線程。
這是一種可以極大提高執(zhí)行程序性能的方式,其中多個(gè)指令線程在相同的進(jìn)程資源上獨(dú)立運(yùn)行。機(jī)器學(xué)習(xí)模型非常適合以這種方式進(jìn)行訓(xùn)練。
只有一個(gè)小問題:GIL 一次只能在一個(gè)線程上工作。因此,如果變量 A 在線程 1 上執(zhí)行,而線程 2 已經(jīng)完成了變量A ,那么它的內(nèi)存可能會(huì)被刪除,這取決于當(dāng)時(shí) GIL 處在什么位置。
正如你想象的那樣,這可能會(huì)導(dǎo)致非常奇怪的錯(cuò)誤。
當(dāng)然,這是有解決方法的,但它們都不是很完美,因?yàn)樗ǔ2粫?huì)像有 GIL 語(yǔ)言中的多線程那樣快。
7、并發(fā)和并行仍然笨重和混亂
我們已經(jīng)發(fā)現(xiàn)了并發(fā)的一個(gè)缺點(diǎn),就是當(dāng)你正在進(jìn)行多線程時(shí),全局解釋器鎖會(huì)減慢速度,或者導(dǎo)致奇怪的錯(cuò)誤。
同樣的缺點(diǎn)也存在于 Python 的協(xié)同程序。
線程和協(xié)程有一些細(xì)微的區(qū)別,即協(xié)程一次執(zhí)行一個(gè)任務(wù),而線程可以同時(shí)執(zhí)行多個(gè)任務(wù)。相同點(diǎn)在于,它們都是并發(fā)的實(shí)現(xiàn)。
當(dāng)你有大量需要等待的任務(wù)時(shí),協(xié)程很有用,比如你正在讀取網(wǎng)站數(shù)據(jù)并等待服務(wù)器響應(yīng)。協(xié)程程序并不會(huì)讓計(jì)算機(jī)坐視不管,而是將另一個(gè)任務(wù)分配給它。另一方面,當(dāng)你有幾個(gè)耗時(shí)的任務(wù)時(shí),線程的優(yōu)勢(shì)就體現(xiàn)出來(lái)了,不太占用 CPU ,也不需要太多等待。
如果你有一個(gè) CPU 密集型任務(wù),并且想要充分利用你的硬件,那么并行是值得考慮的。
多處理也是個(gè)不錯(cuò)的選擇,它會(huì)告訴計(jì)算機(jī)使用多個(gè)核心,節(jié)省時(shí)間。
不過,線程、協(xié)程和多處理這三種技術(shù)都面臨類似的問題,即在 Python 中實(shí)現(xiàn)它們并不難,但是代碼看起來(lái)很笨拙,很難讀懂,尤其是對(duì)于初學(xué)者。
像 Clojure 、 Go 和 Haskell 這樣的語(yǔ)言,在并行性和并發(fā)性方面要好得多。如果你處理的不是緩慢或密集型任務(wù),就無(wú)需考慮。但如果你是,你可能要重新考慮你的選擇。
8、用什么代替Python
Python 自有其不可忽視的優(yōu)勢(shì),但它也的確存在缺點(diǎn)。
如果你想要明確聲明的變量和開發(fā)良好的包,避免陷入依賴地獄,那么 C 就很不錯(cuò)。
如果你想要的東西是可移植到任何機(jī)器的,那么 Java, Clojure 或 Scala 是很好的選擇。它們是在虛擬機(jī)上運(yùn)行的,所以你不會(huì)遇到像 Python 一樣的麻煩。
而如果你想運(yùn)行大型緩慢的任務(wù),你可能會(huì)想試試 Go 或者 Haskell。一開始,它們比 Python 難學(xué),但是你投入的時(shí)間是有回報(bào)的。
你還可以組合不同的語(yǔ)言,比如 Python 非常適合快速編寫腳本、草圖,甚至是中等規(guī)模的項(xiàng)目。我認(rèn)識(shí)的許多開發(fā)人員都是用 Python 編寫第一稿和測(cè)試運(yùn)行,然后用 C 、Go 或 Clojure 重寫重要部分。這可以使代碼執(zhí)行得更快,同時(shí)還可以享受 Python 提供的優(yōu)勢(shì)。
在大型項(xiàng)目中也并不是不能使用 Python,只是很多情況下它并不是唯一:你可以使用 Python 來(lái)拼湊 C 、 Go 或 Clojure 中的各個(gè)部分。
如果你已經(jīng)達(dá)到了自己構(gòu)建的目標(biāo),請(qǐng)記住,沒有任何一種語(yǔ)言是完美的。盡管 Python 有其缺點(diǎn),但它依舊很棒,也很方便,你可以通過集成其他語(yǔ)言的代碼來(lái)避開 Python 這些缺點(diǎn)。
原文地址:https://thenextweb.com/news/dont-use-python-for-big-projects
本文轉(zhuǎn)自公眾號(hào)“CSDN”,ID:CSDNnews
推薦閱讀:
入門:?最全的零基礎(chǔ)學(xué)Python的問題? |?零基礎(chǔ)學(xué)了8個(gè)月的Python??|?實(shí)戰(zhàn)項(xiàng)目?|學(xué)Python就是這條捷徑
干貨:爬取豆瓣短評(píng),電影《后來(lái)的我們》?|?38年NBA最佳球員分析?|? ?從萬(wàn)眾期待到口碑撲街!唐探3令人失望? |?笑看新倚天屠龍記?|?燈謎答題王?|用Python做個(gè)海量小姐姐素描圖?|碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影
趣味:彈球游戲? |?九宮格? |?漂亮的花?|?兩百行Python《天天酷跑》游戲!
AI:?會(huì)做詩(shī)的機(jī)器人?|?給圖片上色?|?預(yù)測(cè)收入?|?碟中諜這么火,我用機(jī)器學(xué)習(xí)做個(gè)迷你推薦系統(tǒng)電影
小工具:?Pdf轉(zhuǎn)Word,輕松搞定表格和水印!?|?一鍵把html網(wǎng)頁(yè)保存為pdf!|??再見PDF提取收費(fèi)!?|?用90行代碼打造最強(qiáng)PDF轉(zhuǎn)換器,word、PPT、excel、markdown、html一鍵轉(zhuǎn)換?|?制作一款釘釘?shù)蛢r(jià)機(jī)票提示器!?|60行代碼做了一個(gè)語(yǔ)音壁紙切換器天天看小姐姐!|
年度爆款文案
點(diǎn)閱讀原文,看B站我的視頻!

