99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁(yè)精彩閱讀python到底是強(qiáng)類型語(yǔ)言,還是弱類型語(yǔ)言?
python到底是強(qiáng)類型語(yǔ)言,還是弱類型語(yǔ)言?
2020-09-02
收藏

作者:豌豆花下貓 

來(lái)源:Python貓

上一篇文章分析了 為什么 python 沒(méi)有 void 類型 的話題,在文章發(fā)布后,有讀者跟我討論起了另一個(gè)關(guān)于類型的問(wèn)題,但是,我們很快就出現(xiàn)了重大分歧。

我們主要的分歧就在于:Python 到底是不是強(qiáng)類型語(yǔ)言?我認(rèn)為是,而他認(rèn)為不是。他寫(xiě)了一篇很長(zhǎng)的文章《誰(shuí)告訴的你們Python是強(qiáng)類型語(yǔ)言!站出來(lái),保證不打你!》,專門重申了他的觀點(diǎn),但可惜錯(cuò)漏百出。

我曾有想法要寫(xiě)寫(xiě)關(guān)于 python 類型的問(wèn)題,現(xiàn)在借著這個(gè)機(jī)會(huì),就來(lái)系統(tǒng)地梳理一下吧。

(PS:在我寫(xiě)作進(jìn)行到差不多一半的時(shí)候,讀者群里恰好也討論到“強(qiáng)弱類型”的話題!在與大家討論時(shí),我的一些想法得到了驗(yàn)證,同時(shí)我也學(xué)到了很多新知識(shí),所以本文的部分內(nèi)容有群友們的功勞,特此鳴謝?。?/em>

1、動(dòng)靜類型與強(qiáng)弱類型

很多讀者應(yīng)該都熟悉動(dòng)態(tài)類型與靜態(tài)類型,但是很多人也會(huì)把它們跟強(qiáng)弱類型混為一談,所以我們有必要先作一下概念上的澄清。

這兩組類型都是針對(duì)于編程語(yǔ)言而言的,但關(guān)注的核心問(wèn)題不同。

對(duì)于“動(dòng)靜類型”概念,它的核心問(wèn)題是“什么時(shí)候知道一個(gè)變量是哪種類型”?

一般而言,在編譯期就確定變量類型的是靜態(tài)類型語(yǔ)言,在運(yùn)行期才確定變量類型的則是動(dòng)態(tài)類型語(yǔ)言。

例如,某些語(yǔ)言中定義函數(shù)“int func(int a){…}”,在編譯時(shí)就能確定知道它的參數(shù)和返回值是 int 類型,所以是靜態(tài)類型;而典型如 Python,定義函數(shù)時(shí)寫(xiě)“def func(a):…”,并不知道參數(shù)和返回值的類型,只有到運(yùn)行時(shí)調(diào)用函數(shù),才最終確定參數(shù)和返回值的類型,所以是動(dòng)態(tài)類型

對(duì)于“強(qiáng)弱類型”概念,它的核心問(wèn)題是“不同類型的變量是否允許隱式轉(zhuǎn)化”?

一般而言,編譯器有很少(合理)隱式類型轉(zhuǎn)化的是強(qiáng)類型語(yǔ)言,有較多(過(guò)分)隱式類型轉(zhuǎn)化的是弱類型語(yǔ)言。  

例如,Javascript 中的 "1000"+1會(huì)得到字符串“10001”,而 "1000"-1則會(huì)得到數(shù)字 999,也就是說(shuō),編譯器根據(jù)使用場(chǎng)合,對(duì)兩種不同類型的對(duì)象分別做了隱式的類型轉(zhuǎn)化,但是相似的寫(xiě)法,在強(qiáng)類型語(yǔ)言中則會(huì)報(bào)類型出錯(cuò)。(數(shù)字與字符串的轉(zhuǎn)化屬于過(guò)分的轉(zhuǎn)化,下文會(huì)再提到一些合理的轉(zhuǎn)化。)

按照以上的定義,有人將常見(jiàn)的編程語(yǔ)言畫(huà)了一張分類圖:

按強(qiáng)弱類型維度劃分,可以歸納出:

  • 強(qiáng)類型:Java、C#、Python、Ruby、Erlang(再加GO、Rust)……
  • 弱類型:C、C++、Javascript、Perl、PHP、VB……

2、過(guò)去的強(qiáng)弱類型概念

動(dòng)靜類型的概念基本上被大家所認(rèn)可,然而,強(qiáng)弱類型的概念在問(wèn)答社區(qū)、技術(shù)論壇和學(xué)術(shù)討論上卻有很多的爭(zhēng)議。此處就不作羅列了。

為什么會(huì)有那么多爭(zhēng)議呢?

最主要的原因之一是有人把它與動(dòng)靜類型混用了。

最明顯的一個(gè)例子就是 Guido van Rossum 在 2003 年參加的一個(gè)訪談,它的話題恰好是關(guān)于強(qiáng)弱類型的(Strong versus Weak Typing):

但是,他們談?wù)摰拿黠@只是動(dòng)靜類型的區(qū)別。

訪談中還引述了 Java 之父 James Gosling 的話,從他的表述中也能看出,他說(shuō)的“強(qiáng)弱類型”其實(shí)也是動(dòng)靜類型的區(qū)分。

另外還有一個(gè)經(jīng)典的例子,C 語(yǔ)言之父 Dennis Ritchie 曾經(jīng)說(shuō) C 語(yǔ)言是一種“強(qiáng)類型但是弱檢查”的語(yǔ)言。如果對(duì)照成前文的定義,那他其實(shí)指的是“靜態(tài)類型弱類型”。

為什么這些大佬們會(huì)有混淆呢?

其實(shí)原因也很簡(jiǎn)單,那就是在當(dāng)時(shí)還沒(méi)有明確的動(dòng)靜類型與強(qiáng)弱類型的概念之分!或者說(shuō),那時(shí)候的強(qiáng)弱類型指的就是動(dòng)靜類型。

維基百科上給出了 1970 年代對(duì)強(qiáng)類型的定義,基本可以還原成前文提到的靜態(tài)類型:

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]

前面幾位編程語(yǔ)言之父應(yīng)該就是持有類似的觀念。

不過(guò),大佬們也意識(shí)到了當(dāng)時(shí)的“強(qiáng)弱類型”概念并不充分準(zhǔn)確,所以 Dennis Ritchie 才會(huì)說(shuō)成“強(qiáng)類型但是弱檢查”,而且在訪談中,Guido 也特別強(qiáng)調(diào)了 Python 不應(yīng)該被稱為弱類型,而應(yīng)該說(shuō)是運(yùn)行時(shí)類型(runtime typing) 。

但是在那個(gè)早期年代,基本上強(qiáng)弱類型就等同于動(dòng)靜類型,而這樣的想法至今仍在影響著很多人。

3、現(xiàn)在的強(qiáng)弱類型概念

早期對(duì)于編程語(yǔ)言的分類其實(shí)是混雜了動(dòng)靜與強(qiáng)弱兩個(gè)維度,但是,它們并不是一一對(duì)應(yīng)重合的關(guān)系,并不足以表達(dá)編程語(yǔ)言間的區(qū)別,因此就需要有更為明確/豐富的定義。

有人提出了“type safety”、“memory safety”等區(qū)分維度,也出現(xiàn)了靜態(tài)檢查類型和動(dòng)態(tài)檢查類型,與強(qiáng)弱類型存在一定的交集。

直到出現(xiàn) 2004 年的一篇集大成的學(xué)術(shù)論文《Type Systems》(出自微軟研究院,作者 Luca Cardelli),專門研究編程語(yǔ)言的不同類型系統(tǒng):

論文中對(duì)于強(qiáng)弱檢查(也即強(qiáng)弱類型)有一個(gè)簡(jiǎn)短的歸納如下:

  • Strongly checked language: A language where no forbidden errors can occur at run time (depending on the definition of forbidden error).
  • Weakly checked language: A language that is statically checked but provides no clear guarantee of absence of execution errors.

其關(guān)鍵則是程序?qū)τ?nbsp;untrapped errors 的檢查強(qiáng)度,在某些實(shí)際已出錯(cuò)的地方,弱類型程序并不作捕獲處理,例如 C 語(yǔ)言的一些指針計(jì)算和轉(zhuǎn)換,而《C 程序員十誡》的前幾個(gè)都是弱類型導(dǎo)致的問(wèn)題。

論文對(duì)于這些概念的定義還是比較抽象的,由于未捕獲的錯(cuò)誤(untrapped errors)大多是由于隱式類型轉(zhuǎn)換所致,所以又演化出了第一節(jié)中的定義,以隱式類型轉(zhuǎn)換作為判斷標(biāo)準(zhǔn)。

如今將“對(duì)隱式類型轉(zhuǎn)換的容忍度”作為強(qiáng)弱類型的分類標(biāo)準(zhǔn),已經(jīng)是很多人的共識(shí)(雖然不夠全面,而且有一些不同的聲音)。

例如,維基百科就把隱式類型轉(zhuǎn)換作為弱類型的主要特點(diǎn)之一:

A weakly typed language has looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime.

例如,以 Python 為例,社區(qū)的主流看法認(rèn)為它是強(qiáng)類型語(yǔ)言,而判斷的標(biāo)準(zhǔn)也是看隱式類型轉(zhuǎn)換。

例子有很多,比如 Python 官方的 wiki,它專門回答了Why is Python a dynamic language and also a strongly typed language ,給出了 4 個(gè)答案,為 Python 的“動(dòng)態(tài)強(qiáng)類型”定性:

再比如,在《流暢的Python》第11章的雜談中,也專門提到了強(qiáng)弱類型的分類。(它的用語(yǔ)是“很少隱式類型轉(zhuǎn)換”,算是比較嚴(yán)謹(jǐn)?shù)?,但是也錯(cuò)誤地把 C++ 歸為了強(qiáng)類型。)

4、Python 是不是強(qiáng)類型語(yǔ)言?

關(guān)于“Python 是否屬于強(qiáng)類型”話題,在主流觀點(diǎn)之外,還存在著不少誤解的看法。

一方面的原因有些人混用了強(qiáng)弱類型與動(dòng)靜類型,這有歷史的原因,前面已經(jīng)分析了。

另外還有一個(gè)同樣重要的原因,即有人把弱類型等同于“完全沒(méi)有隱式類型轉(zhuǎn)換”了,這種想法并不對(duì)。

事實(shí)上,強(qiáng)弱類型的概念中包含著部分相對(duì)主義的含義,強(qiáng)類型語(yǔ)言中也可能有隱式類型轉(zhuǎn)換。

比如,Rust 語(yǔ)言為了實(shí)現(xiàn)“內(nèi)存安全”的設(shè)計(jì)哲學(xué),設(shè)計(jì)了很強(qiáng)大的類型系統(tǒng),但是它里面也有隱式類型轉(zhuǎn)換(自動(dòng)解引用)。

問(wèn)題在于:怎么樣的隱式類型轉(zhuǎn)換是在合理范圍內(nèi)的?以及,某些表面的隱式類型轉(zhuǎn)換,是否真的是隱式類型轉(zhuǎn)換?

回到 Python 的例子,我們可以分析幾種典型的用法。

比如,"test"*3這種字符串“乘法”運(yùn)算,雖然是兩種類型的操作,但是并不涉及隱式類型轉(zhuǎn)換轉(zhuǎn)化。

比如,x=10; x="test"先后給一個(gè)變量不同類型的賦值,表面上看 x 的類型變化了,用 type(x) 可以判斷出不同,但是,Python 中的類型是跟值綁定的(右值綁定),并不是跟變量綁定的。

變量 x 準(zhǔn)確地說(shuō)只是變量名,是綁定到實(shí)際變量上的一個(gè)標(biāo)簽,它沒(méi)有類型。type(x) 判斷出的并不是 x 本身的類型,而是 x 指向的對(duì)象的類型,就像內(nèi)置函數(shù) id(x) 算出的也不是 x 本身的地址,而是實(shí)際的對(duì)象的地址。

比如,1 + True這種數(shù)字與布爾類型的加法運(yùn)算,也沒(méi)有發(fā)生隱式類型轉(zhuǎn)換。因?yàn)?Python 中的布爾類型其實(shí)是整型的子類,是同一種類型?。ㄈ绻幸蓡?wèn),可查閱 PEP-285)

再比如,整數(shù)/布爾值與浮點(diǎn)數(shù)相加,在 Python 中也不需要作顯式類型轉(zhuǎn)換。但是,它的實(shí)現(xiàn)過(guò)程其實(shí)是用了數(shù)字的__add__()方法,Python 中一切皆對(duì)象,數(shù)字對(duì)象也有自己的方法。(其它語(yǔ)言可不一定)

也就是說(shuō),數(shù)字間的算術(shù)運(yùn)算操作,其實(shí)是一個(gè)函數(shù)調(diào)用的過(guò)程,跟其它語(yǔ)言中的算術(shù)運(yùn)算有著本質(zhì)的區(qū)別。

另外,不同的數(shù)字類型雖然在計(jì)算機(jī)存儲(chǔ)層面有很大差異,但在人類眼中,它們是同一種類型(寬泛地分),所以就算發(fā)生了隱式類型轉(zhuǎn)換,在邏輯上也是可以接受的。

最后,還有一個(gè)例子,即 Python 在 if/while 之后的真值判斷,我之前分析過(guò)它的實(shí)現(xiàn)原理,它會(huì)把其它類型的對(duì)象轉(zhuǎn)化成布爾類型的值。

但是,它實(shí)際上也只是函數(shù)調(diào)用的結(jié)果(__bool__() 和 __len__()),是通過(guò)計(jì)算而得出的合理結(jié)果,并不屬于隱式的強(qiáng)制類型轉(zhuǎn)換,不在 untrapped errors 的范疇里。

所以,嚴(yán)格來(lái)說(shuō),前面 5 個(gè)例子中都沒(méi)有發(fā)生類型轉(zhuǎn)換。 浮點(diǎn)數(shù)和真值判斷的例子,直觀上看是發(fā)生了類型轉(zhuǎn)換,但它們其實(shí)是 Python 的特性,是可控的、符合預(yù)期的、并沒(méi)有對(duì)原有類型造成破壞。

退一步講,若放寬“隱式類型轉(zhuǎn)換”的含義,認(rèn)為后兩個(gè)例子發(fā)生了隱式類型轉(zhuǎn)換,但是,它們是通過(guò)嚴(yán)謹(jǐn)?shù)暮瘮?shù)調(diào)用過(guò)程實(shí)現(xiàn)的,也不會(huì)出現(xiàn) forbidden errors,所以還是屬于強(qiáng)檢查類型。

5、其它相關(guān)的問(wèn)題

前文對(duì)概念的含義以及 Python 中的表現(xiàn),作了細(xì)致的分析。接下來(lái),為了邏輯與話題的完整性,我們還需要回答幾個(gè)小問(wèn)題:

(1)能否以“隱式類型轉(zhuǎn)換”作為強(qiáng)弱類型的分類依據(jù)?

明確的分類定義應(yīng)該以《Type Systems》為準(zhǔn),它有一套針對(duì)不同 error 的分類,強(qiáng)弱類型其實(shí)是對(duì)于 forbidden errors 的處理分類。隱式類型轉(zhuǎn)換是其明顯的特征,但并不是全部,也不是唯一的判斷依據(jù)。

本文為了方便理解,使用這個(gè)主要特征來(lái)劃分強(qiáng)弱類型,但是要強(qiáng)調(diào),強(qiáng)類型不是沒(méi)有隱式類型轉(zhuǎn)換,而是可能有很少且合理的隱式類型轉(zhuǎn)換。

(2)假如有其它解釋器令 Python 支持廣泛的隱式類型轉(zhuǎn)換,那 Python 還是強(qiáng)類型語(yǔ)言么?

語(yǔ)言的標(biāo)準(zhǔn)規(guī)范就像是法律,而解釋器是執(zhí)法者。如果有錯(cuò)誤的執(zhí)法解釋,那法律還是那個(gè)法律,應(yīng)該改掉錯(cuò)誤的執(zhí)法行為;如果是法律本身有問(wèn)題(造成了解釋歧義和矛盾,或者該廢棄),那就應(yīng)該修改法律,保證它的確定性(要么是強(qiáng)類型,要么是弱類型)。

(3)為什么說(shuō) Javascript 是弱類型?

因?yàn)樗碾[式類型轉(zhuǎn)換非常多、非常復(fù)雜、非常過(guò)分!比如,Javascript 中123 + null結(jié)果為 123,123 + {}結(jié)果為字符串“123[object Object]”。

另外,它的雙等號(hào)“==”除了有基本的比較操作,還可能發(fā)生多重的隱式類型轉(zhuǎn)換,例如true==['2']判斷出的結(jié)果為 false,而true==['1']的結(jié)果是 true,還有[]==![]和[undefined]==false的結(jié)果都為 true……

(4)C++ 是不是弱類型語(yǔ)言?

前文提到《流暢的Python》中將 C++ 歸為強(qiáng)類型,但實(shí)際上它應(yīng)該被歸為弱類型。C++ 的類型轉(zhuǎn)換是個(gè)非常復(fù)雜的話題,@櫻雨樓 小姐姐曾寫(xiě)過(guò)一個(gè)系列文章做了系統(tǒng)論述,文章地址:如何攻克 C++ 中復(fù)雜的類型轉(zhuǎn)換?、詳解 C++ 的隱式類型轉(zhuǎn)換與函數(shù)重載!、誰(shuí)說(shuō) C++ 的強(qiáng)制類型轉(zhuǎn)換很難懂?

6、小結(jié)

強(qiáng)弱類型概念在網(wǎng)上有比較多的爭(zhēng)議,不僅在 Python 是如此,在 C/C++ 之類的語(yǔ)言更甚。

其實(shí)在學(xué)術(shù)上,這個(gè)概念早已有明確的定義,而且事實(shí)上也被很多人所接納。

那些反對(duì)的聲音大多是因?yàn)楦拍罨煊茫驗(yàn)樗麄兒雎粤肆硪环N對(duì)語(yǔ)言進(jìn)行分類的維度;同時(shí),還有一部分值得注意的原因,即不能認(rèn)為強(qiáng)類型等于“完全無(wú)隱式類型轉(zhuǎn)換”或“只要沒(méi)有xxx隱式類型轉(zhuǎn)換”。

本文介紹了社區(qū)中對(duì)python 的主流分類,同時(shí)對(duì)幾類疑似隱式類型轉(zhuǎn)換的用法進(jìn)行了分析,論證出它是一種強(qiáng)類型語(yǔ)言。

數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼

若不方便掃碼,搜微信號(hào):CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對(duì)象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺(tái)檢測(cè)極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說(shuō)明請(qǐng)參見(jiàn):http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計(jì)時(shí)完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請(qǐng)輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請(qǐng)輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }