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) ,如果我們還是有需要在外部程式設定屬性值的話該怎麼辦呢?這就要替每個屬性設定各自的 settergetter 方法了,例如


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 行就是定義 settergetter 方法的地方,程式執行結果如下



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

下面我們討論設計 __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 ,如果 v2None ,表示呼叫端沒有提供第二個參數,因此把兩個屬性都設定為 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. 封裝是在實體屬性前加上兩個底線,這樣存取或設定實體屬性就得透過 gettersetter 方法。
  3. 若將 __init__() 方法其中的參數設定為 None ,便可依條件判斷來設定實體屬性值。
  4. 關鍵字 is 用來判斷兩個物件是否相等。


問題與討論


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

練習


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

the end

沒有留言: