Python 到底是強類型語言,還是弱類型語言?

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"0、前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我在上一篇文章中分析了 "},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/wWCgwMofSvKBbi3gZLxsAQ","title":""},"content":[{"type":"text","text":"爲什麼 Python 沒有 void 類型"}]},{"type":"text","text":" 的話題,在文章發佈後,有讀者跟我討論起了另一個關於類型的問題,但是,我們很快就出現了重大分歧。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們主要的分歧就在於:"},{"type":"text","marks":[{"type":"strong"}],"text":"Python 到底是不是強類型語言?"},{"type":"text","text":" 我認爲是,而他認爲不是。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"他寫了一篇很長的文章《"},{"type":"link","attrs":{"href":"https://blog.csdn.net/nokiaguy/article/details/108218260","title":""},"content":[{"type":"text","text":"誰告訴的你們Python是強類型語言!站出來,保證不打你!"}]},{"type":"text","text":"》,專門重申了他的觀點,但可惜錯漏百出。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我曾有想法要寫寫關於 Python 類型的問題,現在藉着這個機會,就來系統地梳理一下吧。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(PS:在我寫作進行到差不多一半的時候,微信讀者羣裏恰好也討論到“強弱類型”的話題!在與大家討論時,我的一些想法得到了驗證,同時我也學到了很多新知識,所以本文的部分內容有羣友們的功勞,特此鳴謝!)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1、動靜類型與強弱類型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多讀者應該都熟悉"},{"type":"codeinline","content":[{"type":"text","text":"動態類型"}]},{"type":"text","text":" 與"},{"type":"codeinline","content":[{"type":"text","text":"靜態類型"}]},{"type":"text","text":" ,但是很多人也會把它們跟"},{"type":"codeinline","content":[{"type":"text","text":"強弱類型"}]},{"type":"text","text":" 混爲一談,所以我們有必要先作一下概念上的澄清。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這兩組類型都是針對於編程語言而言的,但關注的核心問題不同。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"對於“動靜類型”概念,它的核心問題是“什麼時候知道一個變量是哪種類型”?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"一般而言,在編譯期就確定變量類型的是靜態類型語言,在運行期才確定變量類型的則是動態類型語言。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,某些語言中定義函數“int func(int a){...}”,在編譯時就能確定知道它的參數和返回值是 int 類型,所以是靜態類型;而典型如 Python,定義函數時寫“def func(a):...”,並不知道參數和返回值的類型,只有到運行時調用函數,才最終確定參數和返回值的類型,所以是動態類型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"對於“強弱類型”概念,它的核心問題是“不同類型的變量是否允許隱式轉化”?"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"一般而言,編譯器有很少(合理)隱式類型轉化的是強類型語言,有較多(過分)隱式類型轉化的是弱類型語言。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,Javascript 中的 "},{"type":"codeinline","content":[{"type":"text","text":"\"1000\"+1"}]},{"type":"text","text":" 會得到字符串“10001”,而 "},{"type":"codeinline","content":[{"type":"text","text":"\"1000\"-1"}]},{"type":"text","text":" 則會得到數字 999,也就是說,編譯器根據使用場合,對兩種不同類型的對象分別做了隱式的類型轉化,但是相似的寫法,在強類型語言中則會報類型出錯。(數字與字符串的轉化屬於過分的轉化,下文會再提到一些合理的轉化。)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"按照以上的定義,有人將常見的編程語言畫了一張分類圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/75/7538742ee715d20503e2a38c3ccb0d61.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"按強弱類型維度的劃分,可以歸納出:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"強類型:Java、C#、Python、Ruby、Erlang(再加GO、Rust)……"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"弱類型:C、C++、Javascript、Perl、PHP、VB……"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2、過去的強弱類型概念"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"動靜類型的概念基本上被大家所認可,然而,強弱類型的概念在問答社區、技術論壇和學術討論上卻有很多的爭議。此處就不作羅列了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲什麼會有那麼多爭議呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"最主要的原因之一是有人把它與動靜類型混用了。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最明顯的一個例子就是 Guido van Rossum 在 2003 年參加的一個訪談,它的話題恰好是關於強弱類型的("},{"type":"link","attrs":{"href":"https://www.artima.com/intv/strongweak.html","title":""},"content":[{"type":"text","text":"Strong versus Weak Typing"}]},{"type":"text","text":"):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/43/4376471890ecb8a4af6b578c5d17604e.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,他們談論的明顯只是動靜類型的區別。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"訪談中還引述了 Java 之父 James Gosling 的話,從他的表述中也能看出,他說的“強弱類型”其實也是動靜類型的區分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外還有一個經典的例子,C 語言之父 Dennis Ritchie 曾經說 C 語言是一種"},{"type":"text","marks":[{"type":"strong"}],"text":"“強類型但是弱檢查”"},{"type":"text","text":"的語言。如果對照成前文的定義,那他其實指的是“靜態類型弱類型”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲什麼這些大佬們會有混淆呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其實原因也很簡單,"},{"type":"text","marks":[{"type":"strong"}],"text":"那就是在當時還沒有明確的動靜類型與強弱類型的概念之分!或者說,那時候的強弱類型指的就是動靜類型。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"維基百科上給出了 1970 年代對強類型的定義,基本可以還原成前文提到的靜態類型:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"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\\]](https://en.wikipedia.org/wiki/Strong"},{"type":"text","marks":[{"type":"italic"}],"text":"and"},{"type":"text","text":"weak_typing#cite_note-2) 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\\]](https://en.wikipedia.org/wiki/Strong"},{"type":"text","marks":[{"type":"italic"}],"text":"and"},{"type":"text","text":"weak_typing#cite_note-3)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面幾位編程語言之父應該就是持有類似的觀念。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過,大佬們也意識到了當時的“強弱類型”概念並不充分準確,所以 Dennis Ritchie 纔會說成"},{"type":"text","marks":[{"type":"strong"}],"text":"“強類型但是弱檢查”,"},{"type":"text","text":"而且在訪談中,Guido 也特別強調了 Python 不應該被稱爲弱類型,而應該說是"},{"type":"text","marks":[{"type":"strong"}],"text":"運行時類型(runtime typing)"},{"type":"text","text":" 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是在那個早期年代,基本上強弱類型就等同於動靜類型,而這樣的想法至今仍在影響着很多人。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3、現在的強弱類型概念"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"早期對於編程語言的分類其實是混雜了動靜與強弱兩個維度,但是,它們並不是一一對應重合的關係,並不足以表達編程語言間的區別,因此就需要有更爲明確/豐富的定義。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有人提出了“type safety”、“memory safety”等區分維度,也出現了靜態檢查類型和動態檢查類型,與強弱類型存在一定的交集。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"直到出現 2004 年的一篇集大成的學術論文《"},{"type":"link","attrs":{"href":"http://lucacardelli.name/Papers/TypeSystems.pdf","title":""},"content":[{"type":"text","text":"Type Systems"}]},{"type":"text","text":"》(出自微軟研究院,作者 Luca Cardelli),專門研究編程語言的不同類型系統:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/066dd2236001f20939d1857a92debed8.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"論文中對於強弱檢查(也即強弱類型)有一個簡短的歸納如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Strongly checked language: A language where no forbidden errors can occur at run time (depending on the definition of forbidden error)."}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Weakly checked language: A language that is statically checked but provides no clear guarantee of absence of execution errors."}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其關鍵則是程序對於 "},{"type":"text","marks":[{"type":"italic"}],"text":"untrapped errors"},{"type":"text","text":" 的檢查強度,在某些實際已出錯的地方,弱類型程序並不作捕獲處理,例如 C 語言的一些指針計算和轉換,而《"},{"type":"link","attrs":{"href":"http://doc.cat-v.org/henry_spencer/ten-commandments","title":""},"content":[{"type":"text","text":"C 程序員十誡"}]},{"type":"text","text":"》的前幾個都是弱類型導致的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/da/da6c29f4f18a25ca16ed4726dc06c1b4.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"論文對於這些概念的定義還是比較抽象的,由於未捕獲的錯誤(untrapped errors)大多是由於隱式類型轉換所致,所以又演化出了第一節中的定義,以隱式類型轉換作爲判斷標準。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如今將"},{"type":"text","marks":[{"type":"strong"}],"text":"“對隱式類型轉換的容忍度”"},{"type":"text","text":"作爲強弱類型的分類標準,已經是很多人的共識(雖然不夠全面,而且有一些不同的聲音)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,維基百科就把隱式類型轉換作爲弱類型的主要特點之一:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"A weakly typed language has looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime."}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例如,以 Python 爲例,"},{"type":"text","marks":[{"type":"strong"}],"text":"社區的主流看法認爲它是強類型語言,而判斷的標準也是看隱式類型轉換。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"例子有很多,比如 Python 官方的 wiki,它專門回答了"},{"type":"link","attrs":{"href":"https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language","title":""},"content":[{"type":"text","text":"Why is Python a dynamic language and also a strongly typed language"}]},{"type":"text","text":" ,給出了 4 個答案,爲 Python 的“動態強類型”定性:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/73/73c928ac9836fde5c1c101d8a6929e08.jpeg","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再比如,在《流暢的Python》第11章的雜談中,也專門提到了強弱類型的分類。(它的用語是“很少隱式類型轉換”,算是比較嚴謹的,但是也錯誤地把 C++ 歸爲了強類型。)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4、Python 是不是強類型語言?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於“Python 是否屬於強類型”話題,在主流觀點之外,還存在着不少誤解的看法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一方面的原因有些人混用了強弱類型與動靜類型,這有歷史的原因,前面已經分析了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外還有一個同樣重要的原因,即有人把弱類型等同於“完全沒有隱式類型轉換”了,這種想法並不對。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"事實上,強弱類型的概念中包含着部分相對主義的含義,強類型語言中也可能有隱式類型轉換。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如,Rust 語言爲了實現“內存安全”的設計哲學,設計了很強大的類型系統,但是它裏面也有隱式類型轉換(自動解引用)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"問題在於:"},{"type":"text","marks":[{"type":"strong"}],"text":"怎麼樣的隱式類型轉換是在合理範圍內的?以及,某些表面的隱式類型轉換,是否真的是隱式類型轉換?"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"回到 Python 的例子,我們可以分析幾種典型的用法。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如,"},{"type":"codeinline","content":[{"type":"text","text":"\"test\"*3"}]},{"type":"text","text":" 這種字符串“乘法”運算,雖然是兩種類型的操作,但是並不涉及隱式類型轉換轉化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如,"},{"type":"codeinline","content":[{"type":"text","text":"x=10; x=\"test\""}]},{"type":"text","text":" 先後給一個變量不同類型的賦值,表面上看 x 的類型變化了,用 type(x) 可以判斷出不同,但是,Python 中的類型是跟值綁定的(右值綁定),並不是跟變量綁定的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"變量 x 準確地說只是變量名,是綁定到實際變量上的一個標籤,它沒有類型。type(x) 判斷出的並不是 x 本身的類型,而是 x 指向的對象的類型,就像內置函數 id(x) 算出的也不是 x 本身的地址,而是實際的對象的地址。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"比如,"},{"type":"codeinline","content":[{"type":"text","text":"1 + True"}]},{"type":"text","text":" 這種數字與布爾類型的加法運算,也沒有發生隱式類型轉換。因爲 Python 中的布爾類型其實是整型的子類,是同一種類型!(如果有疑問,可查閱 "},{"type":"link","attrs":{"href":"https://github.com/chinesehuazhou/peps-cn/blob/master/StandardsTrack/285--%E6%B7%BB%E5%8A%A0%E5%B8%83%E5%B0%94%E7%B1%BB%E5%9E%8B.md","title":""},"content":[{"type":"text","text":"PEP-285"}]},{"type":"text","text":")"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"再比如,整數/布爾值與浮點數相加,在 Python 中也不需要作顯式類型轉換。但是,它的實現過程其實是用了數字的"},{"type":"codeinline","content":[{"type":"text","text":"__add__()"}]},{"type":"text","text":" 方法,Python 中一切皆對象,數字對象也有自己的方法。(其它語言可不一定)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也就是說,"},{"type":"text","marks":[{"type":"strong"}],"text":"數字間的算術運算操作,其實是一個函數調用的過程,跟其它語言中的算術運算有着本質的區別。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"另外,不同的數字類型雖然在計算機存儲層面有很大差異,但在人類眼中,它們是同一種類型(寬泛地分),所以就算髮生了隱式類型轉換,在邏輯上也是可以接受的。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,還有一個例子,即 Python 在 if/while 之後的真值判斷,我之前分析過它的"},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/g6jZX0IdH9xpM7BMV3-ToQ","title":""},"content":[{"type":"text","text":"實現原理"}]},{"type":"text","text":" ,它會把其它類型的對象轉化成布爾類型的值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是,它實際上也只是函數調用的結果(\\"},{"type":"text","marks":[{"type":"italic"}],"text":"\\"},{"type":"text","text":"bool\\"},{"type":"text","marks":[{"type":"italic"}],"text":"\\"},{"type":"text","text":"() 和 \\"},{"type":"text","marks":[{"type":"italic"}],"text":"\\"},{"type":"text","text":"len\\_\\_()),是通過計算而得出的合理結果,並不屬於隱式的強制類型轉換,不在 untrapped errors 的範疇裏。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"所以,嚴格來說,前面 5 個例子中都沒有發生類型轉換。"},{"type":"text","text":" 浮點數和真值判斷的例子,直觀上看是發生了類型轉換,但它們其實是 Python 的特性,是可控的、符合預期的、並沒有對原有類型造成破壞。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"退一步講,若放寬“隱式類型轉換”的含義,認爲後兩個例子發生了隱式類型轉換,但是,它們是通過嚴謹的函數調用過程實現的,也不會出現 forbidden errors,所以還是屬於強檢查類型。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"5、其它相關的問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前文對概念的含義以及 Python 中的表現,作了細緻的分析。接下來,爲了邏輯與話題的完整性,我們還需要回答幾個小問題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(1)能否以“隱式類型轉換”作爲強弱類型的分類依據?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"明確的分類定義應該以《"},{"type":"link","attrs":{"href":"http://lucacardelli.name/Papers/TypeSystems.pdf","title":""},"content":[{"type":"text","text":"Type Systems"}]},{"type":"text","text":"》爲準,它有一套針對不同 error 的分類,強弱類型其實是對於 forbidden errors 的處理分類。隱式類型轉換是其明顯的特徵,但並不是全部,也不是唯一的判斷依據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文爲了方便理解,使用這個主要特徵來劃分強弱類型,但是要強調,強類型不是沒有隱式類型轉換,而是可能有很少且合理的隱式類型轉換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(2)假如有其它解釋器令 Python 支持廣泛的隱式類型轉換,那 Python 還是強類型語言麼?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"語言的標準規範就像是法律,而解釋器是執法者。如果有錯誤的執法解釋,那法律還是那個法律,應該改掉錯誤的執法行爲;如果是法律本身有問題(造成了解釋歧義和矛盾,或者該廢棄),那就應該修改法律,保證它的確定性(要麼是強類型,要麼是弱類型)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(3)爲什麼說 Javascript 是弱類型?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲它的隱式類型轉換非常多、非常複雜、非常過分!比如,Javascript 中"},{"type":"codeinline","content":[{"type":"text","text":"123 + null"}]},{"type":"text","text":" 結果爲 123,"},{"type":"codeinline","content":[{"type":"text","text":"123 + {} "}]},{"type":"text","text":" 結果爲字符串“123[object Object]”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另外,它的雙等號“\\=\\=”除了有基本的比較操作,還可能發生多重的隱式類型轉換,例如"},{"type":"codeinline","content":[{"type":"text","text":"true==['2']"}]},{"type":"text","text":" 判斷出的結果爲 false,而"},{"type":"codeinline","content":[{"type":"text","text":"true==['1']"}]},{"type":"text","text":" 的結果是 true,還有"},{"type":"codeinline","content":[{"type":"text","text":"[]==![]"}]},{"type":"text","text":" 和"},{"type":"codeinline","content":[{"type":"text","text":"[undefined]==false"}]},{"type":"text","text":" 的結果都爲 true……"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"(4)C++ 是不是弱類型語言?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前文提到《流暢的Python》中將 C++ 歸爲強類型,但實際上它應該被歸爲弱類型。C++ 的類型轉換是個非常複雜的話題,@櫻雨樓 小姐姐曾寫過一個系列文章做了系統論述,文章地址:"},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/lJiva3BUJXUV0cpX1dOe2Q","title":""},"content":[{"type":"text","text":"如何攻克 C++ 中複雜的類型轉換?"}]},{"type":"text","text":" 、[詳解 C++ 的隱式類型轉換與函數重載!](https://mp.weixin.qq.com/s/S"},{"type":"text","marks":[{"type":"italic"}],"text":"1KPn"},{"type":"text","text":"GWJ7hmLH19Dajfg) 、[誰說 C++ 的強制類型轉換很難懂?](https://mp.weixin.qq.com/s/q3iwtvqMSp6lNC"},{"type":"text","marks":[{"type":"italic"}],"text":"ZR"},{"type":"text","text":"SP6A) "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"6、小結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"強弱類型概念在網上有比較多的爭議,不僅在 Python 是如此,在 C/C++ 之類的語言更甚。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"其實在學術上,這個概念早已有明確的定義,而且事實上也被很多人所接納。"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那些反對的聲音大多是因爲概念混用,因爲他們忽略了另一種對語言進行分類的維度;同時,還有一部分值得注意的原因,即不能認爲強類型等於“完全無隱式類型轉換”或“只要沒有xxx隱式類型轉換”。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文介紹了社區中對 Python 的主流分類,同時對幾類疑似隱式類型轉換的用法進行了分析,論證出它是一種強類型語言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"文章體現了作者一貫的刨根問底精神,這是“"},{"type":"link","attrs":{"href":"https://github.com/chinesehuazhou/python-whydo","title":""},"content":[{"type":"text","text":"Python爲什麼"}]},{"type":"text","text":"”系列文章的風格,如果你喜歡本文,歡迎訂閱關注!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"相關鏈接"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] 誰告訴的你們Python是強類型語言!站出來,保證不打你!: https://blog.csdn.net/nokiaguy/article/details/108218260"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[2] Strong versus Weak Typing: https://www.artima.com/intv/strongweak.html"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[3] https://en.wikipedia.org/wiki/Strong"},{"type":"text","marks":[{"type":"italic"}],"text":"and"},{"type":"text","text":"weak_typing#cite_note-2"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[4] https://en.wikipedia.org/wiki/Strong"},{"type":"text","marks":[{"type":"italic"}],"text":"and"},{"type":"text","text":"weak_typing#cite_note-3"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[5] Type Systems: http://lucacardelli.name/Papers/TypeSystems.pdf"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[6] C 程序員十誡: http://doc.cat-v.org/henry_spencer/ten-commandments"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[7] Why is Python a dynamic language and also a strongly typed language: https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[8] PEP-285: https://github.com/chinesehuazhou/peps-cn/blob/master/StandardsTrack/285--%E6%B7%BB%E5%8A%A0%E5%B8%83%E5%B0%94%E7%B1%BB%E5%9E%8B.md"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[9] Type Systems: http://lucacardelli.name/Papers/TypeSystems.pdf"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[10] Python爲什麼: https://github.com/chinesehuazhou/python-whydo"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章