程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python中 __init__的通俗解釋是什麼?

編輯:Python

作者:追遠·J
鏈接:https://www.zhihu.com/question/46973549/answer/767530541
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

 

作為典型的面向對象的語言,Python中 定義使用是不可或缺的一部分知識。對於有面向對象的經驗、對實例的概念已經足夠清晰的人,學習Python的這套定義規則不過是語法的遷移。但對新手小白而言,要想相對快速地跨過__init__這道坎,還是結合一個簡單例子來說比較好。

以創建一個“學生”為例,最簡單的語句是

class Student():
pass

當然,這樣定義的類沒有包含任何預定義的數據和功能。除了名字叫Student以外,它沒有體現出任何“學生”應該具有的特點。但它是可用的,上述代碼運行過後,通過類似

stu_1 = Student()

這樣的語句,我們可以創建一個“學生”實例,即一個具體的“學生”對象。

通過class語句定義的類Student,就好像一個“模具”,它可以定義作為一個學生應該具有的各種特點(這裡暫未具體定義);

而在類名Student後加圓括號(),組成一個類似函數調用的形式Student(),則執行了一個叫做實例化的過程,即根據定義好的規則,創建一個包含具體數據的學生對象(實例)。

為了使用創建的學生實例stu_1,我們可以繼續為它添加或修改屬性,比如添加一組成績scores ,由三個整數組成:

stu_1.scores = [80, 90, 85]

但這樣明顯存在很多問題,一旦我們需要處理很多學生實例,比如stu_2, stu_3, ...,這樣不但帶來書寫上的麻煩,還容易帶來錯誤,萬一某些地方scores打錯了,或者干脆忘記了,相應的學生實例就會缺少正確的scores屬性。更重要的是,這樣的scores屬性是暴露出來的,它的使用完全被外面控制著,沒有起到“封裝”的效果,既不方便也不靠譜

一個自然的解決方案是允許我們在執行實例化過程Student()傳入一些參數,以方便且正確地初始化/設置一些屬性值,那麼如何定義這種初始化行為呢?答案就是在類內部定義一個__init__函數。這時,Student的定義將變成(我們先用一段注釋占著__init__函數內的位置)。

class Student():
def __init__(self, score1, score2, score3):
# 相關初始化語句

定義__init__後,執行實例化的過程須變成Student(arg1, arg2, arg3)新建的實例本身,連帶其中的參數,會一並傳給__init__函數自動並執行它。所以__init__函數的參數列表會在開頭多出一項,它永遠指代新建的那個實例對象,Python語法要求這個參數必須要有,而名稱隨意,習慣上就命為self

新建的實例傳給self後,就可以在__init__函數內創建並初始化它的屬性了,比如之前的scores,就可以寫為

class Student():
def __init__(self, score1, score2, score3):
self.scores = [score1, score2, score3]

此時,若再要創建擁有具體成績的學生實例,就只需

stu_1 = Student(80, 90, 85)

此時,stu_1將已經具有設置好的scores屬性。並且由於__init__規定了實例化時的參數,若傳入的參數數目不正確,解釋器可以報錯提醒。你也可以在其內部添加必要的參數檢查,以避免錯誤或不合理的參數傳遞。

在其他方面, __init__就與普通函數無異了。考慮到新手可能對“函數”也掌握得很模糊,這裡特別指出幾個“無異”之處:
獨立的命名空間,也就是說 函數內新引入的變量均為局部變量,新建的實例對象對這個函數來說也只是通過第一參數self從外部傳入的,故無論設置還是使用它的屬性都得利用 self.<屬性名>。如果將上面的初始化語句寫成
scores = [score1, score2, score3](少了 self.),
則只是在函數內部創建了一個scores變量,它在函數執行完就會消失,對新建的實例沒有任何影響;
與此對應, self的屬性名和函數內其他名稱(包括參數)也是不沖突的,所以你可能經常見到類似這種寫法,它正確而且規范。
class Student():
def __init__(self, name, scores):
# 這裡增加了屬性name,並將所有成績作為一個參數scores傳入
# self.name是self的屬性,單獨的name是函數內的局部變量,參數也是局部變量
self.name = name
if len(scores) == 3:
self.scores = scores
else:
self.scores = [0] * 3
從第二參數開始均可設置 變長參數默認值等,相應地將允許實例化過程 Student()中靈活地傳入需要數量的參數;
其他……

說到最後,__init__還是有個特殊之處,那就是它不允許有返回值。如果你的__init__過於復雜有可能要提前結束的話,使用單獨的return就好,不要帶返回值。

上面代碼的執行結果如下:


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved