Photo by AbsolutVision on Unsplash
在淺談Python類別(Class)的文章最後有提到物件導向設計的方法類型有分為三種,嚴格來說還有第四種抽象方法(Abstract Method),這個待介紹Python多型(Polymorphism)設計時,再來詳細介紹。今天要說明的以下三種方法(Method)在物件導向設計(Object-oriented programming)中非常的重要,瞭解其觀念及應用有助於類別(Class)的設計更有彈性且易於維護。
- 實體方法(Instance
Method)
- 類別方法(Class
Method)
- 靜態方法(Static Method)
一、實體方法(Instance
Method)
Python類別(Class)中沒有加任何裝飾詞(Decorator)的方法(Method),至少要有一個self參數,於方法(Method)被呼叫時指向物件(Object),其後可以依需求增加額外參數,如下範例:
#汽車類別
class Cars:
#實體方法(Instance Method)
def drive(self):
print("Drive is instance method.")
實體方法(Instance Method)透過self參數可以自由的存取物件(Object)的屬性(Attribute)及其他方法(Method),藉此來改變物件(Object)的狀態,如下範例:
# 汽車類別
class Cars:
# 建構式
def __init__(self):
self.color = "blue"
# 實體方法(Instance Method)
def drive(self):
print(f"{self} is {self.color}.")
self.message() # 呼叫其他方法
# 實體方法(Instance Method)
def message(self):
print("Message method is called.")
mazda = Cars()
mazda.drive()
執行結果
從執行結果可以看到,我們印出self參數時,結果顯示為Cars類別的物件(Object),也就是說呼叫實體方法(Instance
Method)時,Python編譯器會傳入物件(Object),使得self參數指向該物件(Object)。
另一方面,當透過類別(Class)呼叫實體方法(Instance
Class)時,這會使得Python編譯器無法將self參數指向物件(Object),而發生TypeError的錯誤,如下範例:
# 汽車類別
class Cars:
# 建構式
def __init__(self):
self.color = "blue"
# 實體方法(Instance Method)
def drive(self):
print(f"{self} is {self.color}.")
Cars.drive()
執行結果
# 汽車類別
class Cars:
door = 4 #類別屬性
# 實體方法(Instance Method)
def drive(self):
self.__class__.door = 5
print("Cars original door: ", Cars.door)
mazda = Cars()
mazda.drive()
print("Cars new door: ", Cars.door)
執行結果
範例中實體方法(Instance
Method)即利用self.__class__屬性(Attribute)來改變door類別屬性(Class
Attribute)。
二、 類別方法(Class
Method)
Python類別(Class)中有@classmethod裝飾詞(Decorator)的方法(Method),被呼叫時,相較於實體方法(Instance
Method)的self參數指向物件(Object),類別方法(Class
Method)為cls參數,指向類別(Class),如下範例:
執行結果顯示當類別方法(Instance
Method)被呼叫時,Python編譯器會傳入類別(Class),使得cls參數指向該類別(Class),接著透過cls參數來存取類別屬性(Attribute)。
# 汽車類別
class Cars:
# 類別方法(Class Method)
@classmethod
def open_door(cls):
print("Open door is class method.")
由於類別方法(Class
Method)的cls參數指向類別(Class),所以類別方法(Class
Method)僅能改變類別的狀態,而無法改變物件(Object)的狀態,因為它沒有self參數可以存取物件的屬性(Attribute)及方法(Method)。如下範例:
# 汽車類別
class Cars:
door = 4 # 類別屬性
# 類別方法(Class Method)
@classmethod
def open_door(cls):
print(f"{cls} has {cls.door} doors.")
mazda = Cars()
mazda.open_door() #透過物件呼叫
Cars.open_door() #透過類別呼叫
執行結果
另外,Python的類別方法(Class Method)常應用於產生物件(Object),如下範例:
就像範例中,想要跑車則呼叫跑車類別方法(Class Method)來建立跑車,至於物件(Object)的初始化過程(建造跑車的過程)封裝在類別方法中(Class Method),它會幫我們完成並回傳,就像建立物件(Object)的工廠一樣,所以類別方法(Class Method)也被稱為工廠方法(Factory Method),讓程式碼簡潔且易於維護。
# 汽車類別
class Cars:
# 建構式
def __init__(self, seat, color):
self.seat = seat
self.color = color
# 廂型車
@classmethod
def van(cls):
return cls(6, "black")
# 跑車
@classmethod
def sports_car(cls):
return cls(4, "yellow")
van = Cars.van()
sports_car = Cars.sports_car()
van及sports_car類別方法(Class Method)利用cls參數初始化物件,並且回傳。當然,以這個範例來說,不一定要透過類別方法(Class Method)來建立物件(Object),可以單純透過建構子(Constructor)即可,主要是要表達當建立物件(Object)的邏輯較複雜時,透過類別方法(Class Method)可以將邏輯封裝起來,來源端只要依需求呼叫相應的類別方法(Class Method)來建立物件(Object)即可。就像範例中,想要跑車則呼叫跑車類別方法(Class Method)來建立跑車,至於物件(Object)的初始化過程(建造跑車的過程)封裝在類別方法中(Class Method),它會幫我們完成並回傳,就像建立物件(Object)的工廠一樣,所以類別方法(Class Method)也被稱為工廠方法(Factory Method),讓程式碼簡潔且易於維護。
三、靜態方法(Static
Method)
Python類別中有@staticmethod裝飾詞(Decorator)的方法(Method),可以接受任意的參數,也因為它沒有self及cls參數,所以靜態方法(Static
Method)無法改變類別(Class)及物件(Object)的狀態,如下範例:
來源端不論透過類別(Class)或物件(Object)皆可呼叫,Python編譯器於執行期間(Runtime)不會傳入self及cls參數至靜態方法(Static
Method)。
使用靜態方法(Static Method)有幾個優點是,在開發過程中可以避免新加入的開發人員意外改變類別(Class)或物件(Object)的狀態(因為方法中無self及cls參數),而影響到類別(Class)原始的設計。其二則是靜態方法(Static Method)在類別中是獨立的,所以有助於單元的測試。
# 汽車類別
class Cars:
#靜態方法
@staticmethod
def accelerate():
print("Accelerate is static method.")
靜態方法(Static Method)在類別(Class)中是一個獨立的方法(Method),通常應用於方法(Method)中無需存取物件(Object)的屬性(Attribute)或方法(Method),單純執行傳入參數或功能上運算的情況,如下範例:
# 汽車類別
class Cars:
# 速率靜態方法
@staticmethod
def speed_rate(distance, minute):
return distance / minute
# 透過物件呼叫
van = Cars()
van_rate = van.speed_rate(10000, 20)
print("van rate: ", van_rate)
# 透過類別呼叫
sports_car_rate = Cars.speed_rate(20000, 20)
print("sports car rate: ", sports_car_rate)
執行結果使用靜態方法(Static Method)有幾個優點是,在開發過程中可以避免新加入的開發人員意外改變類別(Class)或物件(Object)的狀態(因為方法中無self及cls參數),而影響到類別(Class)原始的設計。其二則是靜態方法(Static Method)在類別中是獨立的,所以有助於單元的測試。
四、小結
以上就是Python物件導向設計中的三種方法(Method)類型教學,希望透過此文章對於各方法(Method)的觀念及應用有進一步的認識,在練習的過程中若有碰到任何問題或說明不清楚的地方,歡迎留言與我分享!
有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊
講解真的很清楚,期待您的系列文章!
回覆刪除ZMH您好,感謝您的支持鼓勵 :)
刪除感謝分享 看一次就能理解!
回覆刪除謝謝您的支持,非常開心能夠幫助到您 :)
刪除醍醐灌頂!從沒想過class自己也可以有attributes!
回覆刪除講解超清楚!期待閱讀您其他文章!搭配自己在看的影片,您的文章根本就是講義。感謝!
回覆刪除終於看懂類別方法和靜態方法的差別了,感謝您的分享!!
回覆刪除感謝分享,
回覆刪除另外Class method 的第二個範例,
執行結果顯示當類別方法(Instance Method)被呼叫時,Python編譯器會傳入類別(Class),使得cls參數指向該類別(Class),接著透過cls參數來存取類別屬性(Attribute)。
是不是誤打成Instance method了
作者已經移除這則留言。
回覆刪除老師,我想請問一下直接使用 methed 與 function 的需求該怎麼判斷呢?
回覆刪除看起來直接使用 def xxxx(): 也是可以達到與 class 一樣的目的,而且更直接。
不知道有沒有什麼例子可以說明兩著使用時機的差異呢?
請問這句→ 執行結果顯示當類別方法(Instance Method)被呼叫時
回覆刪除Instance Method 是不是打錯了?應該是 Class Method 吧?