
作者:豌豆花下貓
來源:Python貓
上一篇文章分析了 為什么 python 沒有 void 類型 的話題,在文章發布后,有讀者跟我討論起了另一個關于類型的問題,但是,我們很快就出現了重大分歧。
我們主要的分歧就在于:Python 到底是不是強類型語言?我認為是,而他認為不是。他寫了一篇很長的文章《誰告訴的你們Python是強類型語言!站出來,保證不打你!》,專門重申了他的觀點,但可惜錯漏百出。
我曾有想法要寫寫關于 python 類型的問題,現在借著這個機會,就來系統地梳理一下吧。
(PS:在我寫作進行到差不多一半的時候,讀者群里恰好也討論到“強弱類型”的話題!在與大家討論時,我的一些想法得到了驗證,同時我也學到了很多新知識,所以本文的部分內容有群友們的功勞,特此鳴謝?。?/em>
1、動靜類型與強弱類型
很多讀者應該都熟悉動態類型與靜態類型,但是很多人也會把它們跟強弱類型混為一談,所以我們有必要先作一下概念上的澄清。
這兩組類型都是針對于編程語言而言的,但關注的核心問題不同。
對于“動靜類型”概念,它的核心問題是“什么時候知道一個變量是哪種類型”?
一般而言,在編譯期就確定變量類型的是靜態類型語言,在運行期才確定變量類型的則是動態類型語言。
例如,某些語言中定義函數“int func(int a){…}”,在編譯時就能確定知道它的參數和返回值是 int 類型,所以是靜態類型;而典型如 Python,定義函數時寫“def func(a):…”,并不知道參數和返回值的類型,只有到運行時調用函數,才最終確定參數和返回值的類型,所以是動態類型
對于“強弱類型”概念,它的核心問題是“不同類型的變量是否允許隱式轉化”?
一般而言,編譯器有很少(合理)隱式類型轉化的是強類型語言,有較多(過分)隱式類型轉化的是弱類型語言。
例如,Javascript 中的 "1000"+1會得到字符串“10001”,而 "1000"-1則會得到數字 999,也就是說,編譯器根據使用場合,對兩種不同類型的對象分別做了隱式的類型轉化,但是相似的寫法,在強類型語言中則會報類型出錯。(數字與字符串的轉化屬于過分的轉化,下文會再提到一些合理的轉化。)
按照以上的定義,有人將常見的編程語言畫了一張分類圖:
按強弱類型維度劃分,可以歸納出:
2、過去的強弱類型概念
動靜類型的概念基本上被大家所認可,然而,強弱類型的概念在問答社區、技術論壇和學術討論上卻有很多的爭議。此處就不作羅列了。
為什么會有那么多爭議呢?
最主要的原因之一是有人把它與動靜類型混用了。
最明顯的一個例子就是 Guido van Rossum 在 2003 年參加的一個訪談,它的話題恰好是關于強弱類型的(Strong versus Weak Typing):
但是,他們談論的明顯只是動靜類型的區別。
訪談中還引述了 Java 之父 James Gosling 的話,從他的表述中也能看出,他說的“強弱類型”其實也是動靜類型的區分。
另外還有一個經典的例子,C 語言之父 Dennis Ritchie 曾經說 C 語言是一種“強類型但是弱檢查”的語言。如果對照成前文的定義,那他其實指的是“靜態類型弱類型”。
為什么這些大佬們會有混淆呢?
其實原因也很簡單,那就是在當時還沒有明確的動靜類型與強弱類型的概念之分!或者說,那時候的強弱類型指的就是動靜類型。
維基百科上給出了 1970 年代對強類型的定義,基本可以還原成前文提到的靜態類型:
In 1974, Liskov and Zilles defined a strongly-typed language as one in which "whenever an object is passed from a calling function to a called function, its type must be compatible with the type declared in the called function."[3] In 1977, Jackson wrote, "In a strongly typed language each data area will have a distinct type and each process will state its communication requirements in terms of these types."[4]
前面幾位編程語言之父應該就是持有類似的觀念。
不過,大佬們也意識到了當時的“強弱類型”概念并不充分準確,所以 Dennis Ritchie 才會說成“強類型但是弱檢查”,而且在訪談中,Guido 也特別強調了 Python 不應該被稱為弱類型,而應該說是運行時類型(runtime typing) 。
但是在那個早期年代,基本上強弱類型就等同于動靜類型,而這樣的想法至今仍在影響著很多人。
3、現在的強弱類型概念
早期對于編程語言的分類其實是混雜了動靜與強弱兩個維度,但是,它們并不是一一對應重合的關系,并不足以表達編程語言間的區別,因此就需要有更為明確/豐富的定義。
有人提出了“type safety”、“memory safety”等區分維度,也出現了靜態檢查類型和動態檢查類型,與強弱類型存在一定的交集。
直到出現 2004 年的一篇集大成的學術論文《Type Systems》(出自微軟研究院,作者 Luca Cardelli),專門研究編程語言的不同類型系統:
論文中對于強弱檢查(也即強弱類型)有一個簡短的歸納如下:
其關鍵則是程序對于 untrapped errors 的檢查強度,在某些實際已出錯的地方,弱類型程序并不作捕獲處理,例如 C 語言的一些指針計算和轉換,而《C 程序員十誡》的前幾個都是弱類型導致的問題。
論文對于這些概念的定義還是比較抽象的,由于未捕獲的錯誤(untrapped errors)大多是由于隱式類型轉換所致,所以又演化出了第一節中的定義,以隱式類型轉換作為判斷標準。
如今將“對隱式類型轉換的容忍度”作為強弱類型的分類標準,已經是很多人的共識(雖然不夠全面,而且有一些不同的聲音)。
例如,維基百科就把隱式類型轉換作為弱類型的主要特點之一:
A weakly typed language has looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime.
例如,以 Python 為例,社區的主流看法認為它是強類型語言,而判斷的標準也是看隱式類型轉換。
例子有很多,比如 Python 官方的 wiki,它專門回答了Why is Python a dynamic language and also a strongly typed language ,給出了 4 個答案,為 Python 的“動態強類型”定性:
再比如,在《流暢的Python》第11章的雜談中,也專門提到了強弱類型的分類。(它的用語是“很少隱式類型轉換”,算是比較嚴謹的,但是也錯誤地把 C++ 歸為了強類型。)
4、Python 是不是強類型語言?
關于“Python 是否屬于強類型”話題,在主流觀點之外,還存在著不少誤解的看法。
一方面的原因有些人混用了強弱類型與動靜類型,這有歷史的原因,前面已經分析了。
另外還有一個同樣重要的原因,即有人把弱類型等同于“完全沒有隱式類型轉換”了,這種想法并不對。
事實上,強弱類型的概念中包含著部分相對主義的含義,強類型語言中也可能有隱式類型轉換。
比如,Rust 語言為了實現“內存安全”的設計哲學,設計了很強大的類型系統,但是它里面也有隱式類型轉換(自動解引用)。
問題在于:怎么樣的隱式類型轉換是在合理范圍內的?以及,某些表面的隱式類型轉換,是否真的是隱式類型轉換?
回到 Python 的例子,我們可以分析幾種典型的用法。
比如,"test"*3這種字符串“乘法”運算,雖然是兩種類型的操作,但是并不涉及隱式類型轉換轉化。
比如,x=10; x="test"先后給一個變量不同類型的賦值,表面上看 x 的類型變化了,用 type(x) 可以判斷出不同,但是,Python 中的類型是跟值綁定的(右值綁定),并不是跟變量綁定的。
變量 x 準確地說只是變量名,是綁定到實際變量上的一個標簽,它沒有類型。type(x) 判斷出的并不是 x 本身的類型,而是 x 指向的對象的類型,就像內置函數 id(x) 算出的也不是 x 本身的地址,而是實際的對象的地址。
比如,1 + True這種數字與布爾類型的加法運算,也沒有發生隱式類型轉換。因為 Python 中的布爾類型其實是整型的子類,是同一種類型?。ㄈ绻幸蓡?,可查閱 PEP-285)
再比如,整數/布爾值與浮點數相加,在 Python 中也不需要作顯式類型轉換。但是,它的實現過程其實是用了數字的__add__()方法,Python 中一切皆對象,數字對象也有自己的方法。(其它語言可不一定)
也就是說,數字間的算術運算操作,其實是一個函數調用的過程,跟其它語言中的算術運算有著本質的區別。
另外,不同的數字類型雖然在計算機存儲層面有很大差異,但在人類眼中,它們是同一種類型(寬泛地分),所以就算發生了隱式類型轉換,在邏輯上也是可以接受的。
最后,還有一個例子,即 Python 在 if/while 之后的真值判斷,我之前分析過它的實現原理,它會把其它類型的對象轉化成布爾類型的值。
但是,它實際上也只是函數調用的結果(__bool__() 和 __len__()),是通過計算而得出的合理結果,并不屬于隱式的強制類型轉換,不在 untrapped errors 的范疇里。
所以,嚴格來說,前面 5 個例子中都沒有發生類型轉換。 浮點數和真值判斷的例子,直觀上看是發生了類型轉換,但它們其實是 Python 的特性,是可控的、符合預期的、并沒有對原有類型造成破壞。
退一步講,若放寬“隱式類型轉換”的含義,認為后兩個例子發生了隱式類型轉換,但是,它們是通過嚴謹的函數調用過程實現的,也不會出現 forbidden errors,所以還是屬于強檢查類型。
5、其它相關的問題
前文對概念的含義以及 Python 中的表現,作了細致的分析。接下來,為了邏輯與話題的完整性,我們還需要回答幾個小問題:
(1)能否以“隱式類型轉換”作為強弱類型的分類依據?
明確的分類定義應該以《Type Systems》為準,它有一套針對不同 error 的分類,強弱類型其實是對于 forbidden errors 的處理分類。隱式類型轉換是其明顯的特征,但并不是全部,也不是唯一的判斷依據。
本文為了方便理解,使用這個主要特征來劃分強弱類型,但是要強調,強類型不是沒有隱式類型轉換,而是可能有很少且合理的隱式類型轉換。
(2)假如有其它解釋器令 Python 支持廣泛的隱式類型轉換,那 Python 還是強類型語言么?
語言的標準規范就像是法律,而解釋器是執法者。如果有錯誤的執法解釋,那法律還是那個法律,應該改掉錯誤的執法行為;如果是法律本身有問題(造成了解釋歧義和矛盾,或者該廢棄),那就應該修改法律,保證它的確定性(要么是強類型,要么是弱類型)。
(3)為什么說 Javascript 是弱類型?
因為它的隱式類型轉換非常多、非常復雜、非常過分!比如,Javascript 中123 + null結果為 123,123 + {}結果為字符串“123[object Object]”。
另外,它的雙等號“==”除了有基本的比較操作,還可能發生多重的隱式類型轉換,例如true==['2']判斷出的結果為 false,而true==['1']的結果是 true,還有[]==![]和[undefined]==false的結果都為 true……
(4)C++ 是不是弱類型語言?
前文提到《流暢的Python》中將 C++ 歸為強類型,但實際上它應該被歸為弱類型。C++ 的類型轉換是個非常復雜的話題,@櫻雨樓 小姐姐曾寫過一個系列文章做了系統論述,文章地址:如何攻克 C++ 中復雜的類型轉換?、詳解 C++ 的隱式類型轉換與函數重載!、誰說 C++ 的強制類型轉換很難懂?
6、小結
強弱類型概念在網上有比較多的爭議,不僅在 Python 是如此,在 C/C++ 之類的語言更甚。
其實在學術上,這個概念早已有明確的定義,而且事實上也被很多人所接納。
那些反對的聲音大多是因為概念混用,因為他們忽略了另一種對語言進行分類的維度;同時,還有一部分值得注意的原因,即不能認為強類型等于“完全無隱式類型轉換”或“只要沒有xxx隱式類型轉換”。
本文介紹了社區中對python 的主流分類,同時對幾類疑似隱式類型轉換的用法進行了分析,論證出它是一種強類型語言。
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
CDA數據分析師證書考試體系(更新于2025年05月22日)
2025-05-26解碼數據基因:從數字敏感度到邏輯思維 每當看到超市貨架上商品的排列變化,你是否會聯想到背后的銷售數據波動?三年前在零售行 ...
2025-05-23在本文中,我們將探討 AI 為何能夠加速數據分析、如何在每個步驟中實現數據分析自動化以及使用哪些工具。 數據分析中的AI是什么 ...
2025-05-20當數據遇見人生:我的第一個分析項目 記得三年前接手第一個數據分析項目時,我面對Excel里密密麻麻的銷售數據手足無措。那些跳動 ...
2025-05-20在數字化運營的時代,企業每天都在產生海量數據:用戶點擊行為、商品銷售記錄、廣告投放反饋…… 這些數據就像散落的拼圖,而相 ...
2025-05-19在當今數字化營銷時代,小紅書作為國內領先的社交電商平臺,其銷售數據蘊含著巨大的商業價值。通過對小紅書銷售數據的深入分析, ...
2025-05-16Excel作為最常用的數據分析工具,有沒有什么工具可以幫助我們快速地使用excel表格,只要輕松幾步甚至輸入幾項指令就能搞定呢? ...
2025-05-15數據,如同無形的燃料,驅動著現代社會的運轉。從全球互聯網用戶每天產生的2.5億TB數據,到制造業的傳感器、金融交易 ...
2025-05-15大數據是什么_數據分析師培訓 其實,現在的大數據指的并不僅僅是海量數據,更準確而言是對大數據分析的方法。傳統的數 ...
2025-05-14CDA持證人簡介: 萬木,CDA L1持證人,某電商中廠BI工程師 ,5年數據經驗1年BI內訓師,高級數據分析師,擁有豐富的行業經驗。 ...
2025-05-13CDA持證人簡介: 王明月 ,CDA 數據分析師二級持證人,2年數據產品工作經驗,管理學博士在讀。 學習入口:https://edu.cda.cn/g ...
2025-05-12CDA持證人簡介: 楊貞璽 ,CDA一級持證人,鄭州大學情報學碩士研究生,某上市公司數據分析師。 學習入口:https://edu.cda.cn/g ...
2025-05-09CDA持證人簡介 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度、美團、阿里等 ...
2025-05-07相信很多做數據分析的小伙伴,都接到過一些高階的數據分析需求,實現的過程需要用到一些數據獲取,數據清洗轉換,建模方法等,這 ...
2025-05-06以下的文章內容來源于劉靜老師的專欄,如果您想閱讀專欄《10大業務分析模型突破業務瓶頸》,點擊下方鏈接 https://edu.cda.cn/g ...
2025-04-30CDA持證人簡介: 邱立峰 CDA 數據分析師二級持證人,數字化轉型專家,數據治理專家,高級數據分析師,擁有豐富的行業經驗。 ...
2025-04-29CDA持證人簡介: 程靖 CDA會員大咖,暢銷書《小白學產品》作者,13年頂級互聯網公司產品經理相關經驗,曾在百度,美團,阿里等 ...
2025-04-28CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-27數據分析在當今信息時代發揮著重要作用。單因素方差分析(One-Way ANOVA)是一種關鍵的統計方法,用于比較三個或更多獨立樣本組 ...
2025-04-25CDA持證人簡介: 居瑜 ,CDA一級持證人國企財務經理,13年財務管理運營經驗,在數據分析就業和實踐經驗方面有著豐富的積累和經 ...
2025-04-25