Python 入門指南

單元 11 - __init__() 方法

~~學習進度表~~

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

__init__()
__str__()

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

class Demo:
  def __init__(self, v1=11, v2=22):
    self.__a = v1
    self.__b = v2
    
  def do_something(self):
    return self.__a + self.__b
    
d = Demo(12, 34)
print(d.do_something())

#《程式語言教學誌》的範例程式
# https://kaiching.org/
# 檔名:class_demo6.py
# 功能:示範 Python 中的類別
# 作者:張凱慶 */

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

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

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

d = Demo(12, 34)

執行結果如下

$ python claee_demo6.py
46 
$

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

class Demo:
  def __init__(self, v1=11, v2=22):
    self.__a = v1
    self.__b = v2
    
  def get_a(self):
    return self.__a
    
  def get_b(self):
    return self.__b
    
  def set_a(self, value):
    self.__a = value
    
  def set_b(self, value):
     self.__b = value
     
  def do_something(self):
    return self.__a + self.__b
    
d = Demo(11)
print(d.do_something())
d.set_a(5)
print(d.do_something())

#《程式語言教學誌》的範例程式
# https://kaiching.org/
# 檔名:class_demo7.py
# 功能:示範 Python 中的類別
# 作者:張凱慶 */

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

$ python
33
27
$

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

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

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

d = Demo(80, 80)

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

d = Demo(11, 11)

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

class Demo:
  def __init__(self, v1=11, v2=None):
    if v2 is None:
      self.__b = v1
      self.__a = v1
    else:
      self.__a = v1
      self.__b = v2
      
  def do_something(self):
    return self.__a + self.__b
      
d1 = Demo()
print(d1.do_something())
d2 = Demo(13, 12)
print(d2.do_something())

#《程式語言教學誌》的範例程式
# https://kaiching.org/
# 檔名:class_demo8.py
# 功能:示範 Python 中的類別
# 作者:張凱慶 */

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

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

def __init__(self, v1=11, v2=None):
  if v2 is None:
    self.__b = v1
    self.__a = v1
  else:
    self.__a = v1
    self.__b = v2

先判斷第二個參數 v2 是否為 None ,如果 v2None ,表示呼叫端沒有提供第二個參數,因此把兩個屬性都設定為 v1 ,反之 __a 設定成 v1__b 設定為 v2

執行結果如下

$ python
22
25
$

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

中英文術語對照
屬性attribute
類別class
封裝encapsulate
函數function
識別字identifier
程式庫library
方法method
模組module
物件object
多載overload
參數parameter
參數列parameter list
型態type
變數variable
重點整理
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__() 方法。

上一頁 單元 10 - 物件導向與封裝
回 Python 入門指南首頁
下一頁 單元 12 - 模組
回 Python 教材首頁
回程式語言教材首頁