不少人認為 Python 友善掌握,而且不易出錯。然而,并非所有人都同意這個觀點。
許多進階開發表示,使用動态類型的語言實在很令人頭疼:
“什麼?動态類型的語言比靜态類型的語言更加不容易出錯?抱歉,21年的軟體開發職業生涯告訴我并不是這樣。”
—— Rasmus Schultz
在本文中,我們就來看一看進階開發人員不喜歡動态類型語言的主要原因,同時我也希望通過本文消除大家的誤解。
為了更好地挖掘背後的原因,以及鑒于 Python 的廣泛普及,我們以 Python 為例來分析一下。
動态類型
這裡所說的動态類型指的是資料類型。
程式設計語言包含多種類型的風格,比如強類型和鴨子類型等。但是,在本文中我們隻讨論兩個最常見的類型:
- 靜态類型
動态類型指的是在運作時檢查類型錯誤。也就是說不需要顯式聲明資料類型。Python、Ruby 和 JavaScript 都是這類語言。
與動态類型相反,靜态類型則會在編譯期間報告類型錯誤,是以你需要顯式聲明資料類型。C、C++ 和 Java 就屬于這種情況。
一般來說,Python 以及其他程式設計語言的某些優點也會成為缺點。
動态類型可以通過隐式的資料類型聲明減少一部分代碼,進而讓程式設計變得更容易。但是,這個特性也有一些缺陷。
請考慮如下 Python 代碼:
- max_number = 12
- my_list = []
- for i in range(1, 5):
- max_numbre = 2 * (max_number * i)
- my_list.append(max_number)
- print(my_list)
- 輸出結果:
- [12, 12, 12, 12]
在這個例子中,我們希望針對變量 max_number 進行一些計算,并将結果存儲在清單中。但是,我們可以看到實際的操作并不符合我們的預期,而結果也是錯誤的。因為在 for 循環中,max_number 的拼寫有誤,是以導緻程式建立了另一個名為 max_numbre 的變量。
任何人都可能犯這樣的錯誤,特别是對于工作壓力很大的人。
假設你正在編寫一大段代碼,那麼你必須更加小心手指按下的每一個按鍵。否則,查找代碼中的bug就會成為噩夢,并引發維護性的問題。
然而,在靜态類型的語言(比如C++)中,你必須在使用前聲明變量。而且你必須在執行代碼前進行分析,以確定變量類型比對。這樣你對變量的控制會更有力,是以可以提高安全性。
全局解釋器鎖
進階開發人員對動态類型語言的另一個質疑是性能。
初級開發人員隻需要處理好幾行代碼,而維護和編寫健壯的生産代碼(幾百行~幾千行)的重任一般都由經驗豐富的進階開發人員承擔。是以,對他們來說,程式設計語言的效率不容置疑。
由于全局解釋器鎖(Global Interpreter Lock,即 GIL)的存在,計算機的資源(主要是 CPU 線程數)得不到充分利用,是以它是程式設計語言(如 Python 和 MRI Ruby 等)的性能瓶頸。
不過,不使用 GIL 的程式設計語言可以充分利用 CPU 的功能,因為它們支援并行計算。
并行計算隻不過是讓所有線程同時運作而已。在需要處理的資料量十分龐大時,這種類型的計算會比較有優勢。
下圖是一個并行計算的示例:

圖:所有 CPU 一起運作的示例
我們可以假設,在相同的 CPU 時脈速度下,計算機擁有的線程越多,程式的運作速度就越快。
然而,GIL 的出現終結了并行計算。
GIL 的作用是保證一次隻有一個線程使用 GIL。線程的選擇遵循排隊方式。這意味着,當擁有最高優先級的線程正在使用 GIL 時,其他線程将處于等待狀态,直到 GIL 被釋放。
最重要的是,使用者無法控制線程的選擇。隻能由作業系統負責線程優先級的排序,如下圖所示:
為了解決這個問題,許多程式員都嘗試手動在多個線程之間拆分程序,比如 Python 的 multithreading 子產品,就是為了獲得更好的性能。然而,最終的結果卻是性能更差了。
這個結果有點奇怪,如果你想搞清楚事情的始末,則必須再深入研究一下。
盡管 Python 的核心開發團隊已經意識到了這個問題,但是想擺脫 GIL 太難了,因為它是許多 Python 功能的基礎,例如記憶體管理和C擴充等等。
Python 的作者 Guido van Rossum 表示,他不确定 Python 是否會支援并行計算,因為這歸根結底是語言設計層面的問題。
但是,C++ 等靜态類型語言不受 GIL 的限制,是以它們的效率相對更高。
空白的敏感度
錯誤地使用空白就會報錯,并不是每個人都喜歡這樣的程式設計語言。空白不僅包括空格,還包括制表符、換行、傳回或換頁等。例如,與C不同,Python 對空格就非常敏感。
下面,我們就來比較一下 C 和 Python 代碼。
Python 示例:
- i = 50
- if i % 2 == 0:
- print("inside if statement") print("i is even")
- ^
- SyntaxError: invalid syntax
C 示例:
- #include<stdio.h>
- int main(void)
- {int i = 50;
- if (i % 2 == 0)
- ~/ $ ./test1
- inside if statement
- i is even
C 的代碼結構無論再怎麼混亂,都可以得到正确的輸出,而 Python 生成的文法錯誤隻是因為語句的書寫位置有誤。是以,有人可能會說 Python 的健壯性不如 C++ 或 C。
盡管許多專業程式員都認為空白過于敏感很讨人厭,但許多 Python 專家則認為,空白的問題總好過代碼長得看不到盡頭。
最後,在處理大塊代碼時,空白的敏感性問題确實很煩人。但是,如果能夠向團隊灌輸良好的編碼習慣,則這個問題也很好解決。
向後相容
不支援向後相容意味着舊版的 Python 代碼無法在新版本中正常工作。換句話說,每當新版本釋出時,你都需要找出文法的變化,并重寫相應的部分代碼。
有時,向後相容性會成為一個嚴重的問題,Python 2 到 Python 3 就是一個很好的例子。
Python 核心開發團隊認為,将 Python 2 的代碼轉換成 Python 3 不會有任何問題。但是他們錯了。
Python 的作者也承認了這一點:
“我們低估了有多少人已經編寫了大量的 Python 代碼,而且他們已經基本忘記了代碼的工作方式。是以,他們沒能很好地更新這些代碼。我們已經意識到了這個問題。”
這個問題争論到最後,他們決定延長 Python 2.7 的壽命。
總結
程式設計語言一直是一個熱門話題,這不是一個非黑即白的兩極分化問題。我們會因為某些原因而偏愛某一種程式設計語言。
通常,每種通用程式設計語言都有特定的适合人群。Python 的官方作者曾說:
“學習使用 Python 程式設計比學習使用 Java 或 Swift 要容易得多。Java 和 Swift 非常适合計算機科學的專業軟體開發人員。但是 Python 更适合孩子的教學。”
話雖如此,我們非常希望能夠出現一種兼具C++ 和 Python 優點的程式設計語言。