Python 入門指南 V2.00 - 單元 11 - __init__() 方法




Python 中有一些特別的方法 (method) ,這些方法的識別字 (identifier) 前後都用兩個底線圍起來



每一種都有特定的功能,其中的 __init__() 方法就是物件 (object) 建立時所執行的方法,舉例如下


001class Demo:
002   def __init__(self, v1=11, v2=22):
003      self.__a = v1
004      self.__b = v2
005   
006   def do_something(self):
007      return self.__a + self.__b
008
009d = Demo(12, 34)
010print(d.do_something())
011 
012# 檔名: class_demo6.py 
013# 作者: Kaiching Chang 
014# 時間: July, 2014

這裡把原本的 set_att() 改成 __init__()


002def __init__(self, v1=11, v2=22):
003   self.__a = v1
004   self.__b = v2

建立 Demo 型態 (type) 的變數 (variable) d 時就像呼叫 set_att() 一樣,可以直接提供參數設定屬性 (attribute) __a 及 __b


009d = Demo(12, 34)

執行結果如下



屬性都已封裝 (encapsulate) ,如果我們還是有需要在外部程式設定屬性值的話該怎麼辦呢?這就要替每個屬性設定各自的 setter 與 getter 方法了,例如


001class Demo:
002   def __init__(self, v1=11, v2=22):
003      self.__a = v1
004      self.__b = v2
005
006   def get_a(self):
007      return self.__a
008
009   def get_b(self):
010      return self.__b
011
012   def set_a(self, value):
013      self.__a = value
014
015   def set_b(self, value):
016      self.__b = value
017   
018   def do_something(self):
019      return self.__a + self.__b
020
021d = Demo(11)
022print(d.do_something())
023d.set_a(5)
024print(d.do_something())
025 
026# 檔名: class_demo7.py 
027# 作者: Kaiching Chang 
028# 時間: July, 2014

setter 是設定屬性的方法, getter 則是取得屬性的方法,上面 6 到 16 行就是定義 setter 與 getter 方法的地方,程式執行結果如下



如果是用 @property 、 @a.setter 與 @b.setter 標記 setter 與 getter 的話,程式行為就會回到預設的情況。

下面我們討論設計 __init__() 方法的技巧,同樣也適用在函數 (function) 的參數列 (parameter list) 。一個簡單的問題,參數 (parameter) 可以有預設值,這樣建立物件時無須提供參數,可是預設值不見得每一個都可以設定一樣,可是有時候我們只是想要把兩個屬性設定成相同的值說。


如果按照我們上面的設計,兩個屬性都想設定一樣的值,就變成兩個參數都得提供


   d = Demo(80, 80)

更麻煩的是如果希望兩個屬性都跟某個預設值一樣,仍然是兩個參數都得提供


   d = Demo(11, 11)

可不可以簡單一點呢?可以的,我們可以把第二個參數的預設值改成 None ,然後加入條件判斷,如下


001class Demo:
002   def __init__(self, v1=11, v2=None):
003      if v2 is None:
004         self.__a = v1
005         self.__b = v1
006      else:
007         self.__a = v1
008         self.__b = v2
009
010   def do_something(self):
011      return self.__a + self.__b
012
013d1 = Demo()
014print(d1.do_something())
015d2 = Demo(13, 12)
016print(d2.do_something())
017 
018# 檔名: class_demo8.py 
019# 作者: Kaiching Chang 
020# 時間: July, 2014

這樣的技巧在其他強型態的物件導向程式語言中被稱為多載 (overload) ,也就是函數可以定義多個參數版本,因為這些語言所有參數的型態都是固定的,如果需要不同的型態就得宣告其他參數版本的函數或方法。

None 為識別字之一,表示什麼都不是的物件。其中 __init__() 方法


002def __init__(self, v1=11, v2=None):
003   if v2 is None:
004      self.__a = v1
005      self.__b = v1
006   else:
007      self.__a = v1
008      self.__b = v2

關鍵字 is 用來判斷兩個物件是否相等,這裡為判斷第二個參數 v2 是否為 None ,如果 v2 是 None ,表示呼叫端沒有提供第二個參數,因此把兩個屬性都設定為 v1 ,反之 __a 設定成 v1 , __b 設定為 v2 。


執行結果如下



類別 (class) 的介紹到這裡先到一個段落了,由於一個 Python 檔案就是一個獨立的模組 (module) ,眾多模組集合起來就是個模組庫 (library) 了,接下來我們繼續討論模組囉!


中英文術語對照


方法method
識別字identifier
物件object
型態type
變數variable
屬性attribute
封裝encapsulate
函數function
參數列parameter list
參數parameter
多載overload
類別class
模組module
模組庫library

重點整理


  1. __init__() 方法是物件建立時所執行的方法,主要用來初始化實體屬性。
  2. 封裝是在實體屬性前加上兩個底線,這樣存取或設定實體屬性就得透過 getter 或 setter 方法。
  3. 若將 __init__() 方法其中的參數設定為 None ,便可依條件判斷來設定實體屬性值。
  4. 關鍵字 is 用來判斷兩個物件是否相等。


問題與討論


  1. 類別中自訂 __init__() 方法有什麼優點?
  2. 為什麼 Python 的屬性要預設為可以公開存取?
  3. 要怎麼替方法建立不同的參數版本?

練習


  1. 寫一個程式 exercise1101.py ,替 exercise1001.py 的 IntegerDemo 設計 __init__() 方法。
  2. 寫一個程式 exercise1102.py ,替 exercise1002.py 計算階層值的類別設計 __init__() 方法。
  3. 寫一個程式 exercise1103.py ,替 exercise1003.py 計算費氏數列的類別設計 __init__() 方法。

the end

沒有留言: