前言 作為典型的面向?qū)ο?/strong>的語(yǔ)言,Python中 類(lèi) 的定義和使用是不可或缺的一部分知識(shí)。對(duì)于有面向?qū)ο蟮慕?jīng)驗(yàn)、對(duì)類(lèi)和實(shí)例的概念已經(jīng)足夠清晰的人,學(xué)習(xí)Python的這套定義規(guī)則不過(guò)是語(yǔ)法的遷移。但對(duì)新手小白而言,要想相對(duì)快速地跨過(guò)__init__這道坎,還是結(jié)合一個(gè)簡(jiǎn)單例子來(lái)說(shuō)比較好。 以創(chuàng)建一個(gè)“學(xué)生”類(lèi)為例,最簡(jiǎn)單的語(yǔ)句是 class Student(): pass 當(dāng)然,這樣定義的類(lèi)沒(méi)有包含任何預(yù)定義的數(shù)據(jù)和功能。除了名字叫Student以外,它沒(méi)有體現(xiàn)出任何“學(xué)生”應(yīng)該具有的特點(diǎn)。但它是可用的,上述代碼運(yùn)行過(guò)后,通過(guò)類(lèi)似 stu_1 = Student() 這樣的語(yǔ)句,我們可以創(chuàng)建一個(gè)“學(xué)生”實(shí)例,即一個(gè)具體的“學(xué)生”對(duì)象。 通過(guò)class語(yǔ)句定義的類(lèi)Student,就好像一個(gè)“模具”,它可以定義作為一個(gè)學(xué)生應(yīng)該具有的各種特點(diǎn)(這里暫未具體定義); 而在類(lèi)名Student后加圓括號(hào)(),組成一個(gè)類(lèi)似函數(shù)調(diào)用的形式Student(),則執(zhí)行了一個(gè)叫做實(shí)例化的過(guò)程,即根據(jù)定義好的規(guī)則,創(chuàng)建一個(gè)包含具體數(shù)據(jù)的學(xué)生對(duì)象(實(shí)例)。 為了使用創(chuàng)建的學(xué)生實(shí)例stu_1,我們可以繼續(xù)為它添加或修改屬性,比如添加一組成績(jī)scores ,由三個(gè)整數(shù)組成: stu_1.scores = [80, 90, 85] 但這樣明顯存在很多問(wèn)題,一旦我們需要處理很多學(xué)生實(shí)例,比如stu_2, stu_3, ...,這樣不但帶來(lái)書(shū)寫(xiě)上的麻煩,還容易帶來(lái)錯(cuò)誤,萬(wàn)一某些地方scores打錯(cuò)了,或者干脆忘記了,相應(yīng)的學(xué)生實(shí)例就會(huì)缺少正確的scores屬性。更重要的是,這樣的scores屬性是暴露出來(lái)的,它的使用完全被外面控制著,沒(méi)有起到“封裝”的效果,既不方便也不靠譜。 一個(gè)自然的解決方案是允許我們?cè)趫?zhí)行實(shí)例化過(guò)程Student()時(shí)傳入一些參數(shù),以方便且正確地初始化/設(shè)置一些屬性值,那么如何定義這種初始化行為呢?答案就是在類(lèi)內(nèi)部定義一個(gè)__init__函數(shù)。這時(shí),Student的定義將變成(我們先用一段注釋占著__init__函數(shù)內(nèi)的位置)。 定義__init__后,執(zhí)行實(shí)例化的過(guò)程須變成Student(arg1, arg2, arg3),新建的實(shí)例本身,連帶其中的參數(shù),會(huì)一并傳給__init__函數(shù)自動(dòng)并執(zhí)行它。所以__init__函數(shù)的參數(shù)列表會(huì)在開(kāi)頭多出一項(xiàng),它永遠(yuǎn)指代新建的那個(gè)實(shí)例對(duì)象,Python語(yǔ)法要求這個(gè)參數(shù)必須要有,而名稱(chēng)隨意,習(xí)慣上就命為self。 新建的實(shí)例傳給self后,就可以在__init__函數(shù)內(nèi)創(chuàng)建并初始化它的屬性了,比如之前的scores,就可以寫(xiě)為 此時(shí),若再要?jiǎng)?chuàng)建擁有具體成績(jī)的學(xué)生實(shí)例,就只需 stu_1 = Student(80, 90, 85) 此時(shí),stu_1將已經(jīng)具有設(shè)置好的scores屬性。并且由于__init__規(guī)定了實(shí)例化時(shí)的參數(shù),若傳入的參數(shù)數(shù)目不正確,解釋器可以報(bào)錯(cuò)提醒。你也可以在其內(nèi)部添加必要的參數(shù)檢查,以避免錯(cuò)誤或不合理的參數(shù)傳遞。 在其他方面,__init__就與普通函數(shù)無(wú)異了??紤]到新手可能對(duì)“函數(shù)”也掌握得很模糊,這里特別指出幾個(gè)“無(wú)異”之處: 獨(dú)立的命名空間,也就是說(shuō)函數(shù)內(nèi)新引入的變量均為局部變量,新建的實(shí)例對(duì)象對(duì)這個(gè)函數(shù)來(lái)說(shuō)也只是通過(guò)第一參數(shù)self從外部傳入的,故無(wú)論設(shè)置還是使用它的屬性都得利用self.<屬性名 >。如果將上面的初始化語(yǔ)句寫(xiě)成 scores = [score1, score2, score3](少了self.), 則只是在函數(shù)內(nèi)部創(chuàng)建了一個(gè)scores變量,它在函數(shù)執(zhí)行完就會(huì)消失,對(duì)新建的實(shí)例沒(méi)有任何影響; 與此對(duì)應(yīng),self的屬性名和函數(shù)內(nèi)其他名稱(chēng)(包括參數(shù))也是不沖突的,所以你可能經(jīng)常見(jiàn)到類(lèi)似這種寫(xiě)法,它正確而且規(guī)范。 從第二參數(shù)開(kāi)始均可設(shè)置變長(zhǎng)參數(shù)、默認(rèn)值等,相應(yīng)地將允許實(shí)例化過(guò)程Student()中靈活地傳入需要數(shù)量的參數(shù); 其他…… 說(shuō)到最后,__init__還是有個(gè)特殊之處,那就是它不允許有返回值。如果你的__init__過(guò)于復(fù)雜有可能要提前結(jié)束的話(huà),使用單獨(dú)的return就好,不要帶返回值。 上面代碼的執(zhí)行結(jié)果如下 著作權(quán)歸作者所有
|
|