Python 中有一些特別的方法 (method) ,這些方法的識別字 (identifier) 前後都用兩個底線圍起來,最基本的是以下這兩個
__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())
#《程式語言教學誌》的範例程式
# http://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) ,如果我們還是有需要在外部程式設定屬性值的話該怎麼辦呢?這就要替每個屬性設定各自的 setter 與 getter 方法了,例如
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())
#《程式語言教學誌》的範例程式
# http://kaiching.org/
# 檔名:class_demo7.py
# 功能:示範 Python 中的類別
# 作者:張凱慶 */
setter 是設定屬性的方法, getter 則是取得屬性的方法,上面 6 到 16 行就是定義 setter 與 getter 方法的地方,程式執行結果如下
$ python |
33 |
27 |
$ |
如果是用 @property 、 @a.setter 與 @b.setter 標記 setter 與 getter 的話,程式行為就會回到預設的情況。
下面我們討論設計 __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())
#《程式語言教學誌》的範例程式
# http://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 ,如果 v2 是 None ,表示呼叫端沒有提供第二個參數,因此把兩個屬性都設定為 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. 封裝是在實體屬性前加上兩個底線,這樣存取或設定實體屬性就得透過 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__() 方法。 |
相關教學影片