跳到主要內容

[Python物件導向]解析Python物件導向設計的3種類型方法(Instance,Class,Static Method)

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()
執行結果
另外,在實體方法(Instance Method)中可以透過self.__class__屬性(Attribute)來改變類別(Class)的狀態,如下範例:

# 汽車類別
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),如下範例:

# 汽車類別
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()  #透過類別呼叫
執行結果
執行結果顯示當類別方法(Instance Method)被呼叫時,Python編譯器會傳入類別(Class),使得cls參數指向該類別(Class),接著透過cls參數來存取類別屬性(Attribute)

另外,Python的類別方法(Class Method)常應用於產生物件(Object),如下範例:

# 汽車類別
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),可以接受任意的參數,也因為它沒有selfcls參數,所以靜態方法(Static Method)無法改變類別(Class)及物件(Object)的狀態,如下範例:

# 汽車類別
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)
執行結果
來源端不論透過類別(Class)或物件(Object)皆可呼叫,Python編譯器於執行期間(Runtime)不會傳入selfcls參數至靜態方法(Static Method)

使用靜態方法(Static Method)有幾個優點是,在開發過程中可以避免新加入的開發人員意外改變類別(Class)或物件(Object)的狀態(因為方法中無self及cls參數),而影響到類別(Class)原始的設計。其二則是靜態方法(Static Method)在類別中是獨立的,所以有助於單元的測試。

四、小結

以上就是Python物件導向設計中的三種方法(Method)類型教學,希望透過此文章對於各方法(Method)的觀念及應用有進一步的認識,在練習的過程中若有碰到任何問題或說明不清楚的地方,歡迎留言與我分享!

如果您喜歡我的文章,請幫我按五下Like(使用GoogleFacebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。


有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊










留言

  1. 講解真的很清楚,期待您的系列文章!

    回覆刪除
  2. 感謝分享 看一次就能理解!

    回覆刪除
    回覆
    1. 謝謝您的支持,非常開心能夠幫助到您 :)

      刪除
  3. 醍醐灌頂!從沒想過class自己也可以有attributes!

    回覆刪除
  4. 講解超清楚!期待閱讀您其他文章!搭配自己在看的影片,您的文章根本就是講義。感謝!

    回覆刪除
  5. 終於看懂類別方法和靜態方法的差別了,感謝您的分享!!

    回覆刪除
  6. 感謝分享,
    另外Class method 的第二個範例,
    執行結果顯示當類別方法(Instance Method)被呼叫時,Python編譯器會傳入類別(Class),使得cls參數指向該類別(Class),接著透過cls參數來存取類別屬性(Attribute)。
    是不是誤打成Instance method了

    回覆刪除
  7. 作者已經移除這則留言。

    回覆刪除
  8. 老師,我想請問一下直接使用 methed 與 function 的需求該怎麼判斷呢?
    看起來直接使用 def xxxx(): 也是可以達到與 class 一樣的目的,而且更直接。

    不知道有沒有什麼例子可以說明兩著使用時機的差異呢?

    回覆刪除
  9. 請問這句→ 執行結果顯示當類別方法(Instance Method)被呼叫時
    Instance Method 是不是打錯了?應該是 Class Method 吧?

    回覆刪除

張貼留言