Python的程序結構(2) -> 方法/Method -> 靜態方法、類方法和屬性方法
靜態方法、類方法和屬性方法
在 Python 中有三種常用的方法裝飾器(參考裝飾器部分內容),可以使普通的類實例方法變成帶有特殊功能的方法,分別是靜態方法、類方法和屬性方法。
靜態方法 / Static Method
在 def 定義之前加上 @staticmethod 進行裝飾,便可以使該方法成為靜態方法,靜態方法無法調用實例屬性。靜態方法可以通過實例或類進行調用。通常用於無需生成實例或無需共享實例屬性的方法中,比如一些純粹的數學公式計算等場合。
1 class Foo(): 2 @staticmethod 3 def foo(a, b): 4 print(‘This is a staticmethod, cal result: %d‘ % (a+b)) 5 6 Foo.foo(1, 2) 7 Foo().foo(3, 4)
代碼中定義了一個簡單的 Foo 類,並通過添加靜態方法裝飾器定義了一個 foo 靜態方法,該方法會顯示出傳入的兩個參數的計算結果,由於整個方法中不需要用到實例或實例的屬性,因此可以定義為一個靜態方法。
This is a staticmethod, cal result: 3 This is a staticmethod, cal result: 7
從輸出的結果看到,無論是使用類還是類實例,都可以對靜態方法進行調用。
類方法 / Class Method
在 def 定義之前加上 @classmethod 進行裝飾,使得該方法成為類方法,類方法同樣無法調用實例屬性, 但是可以調用類屬性,類方法可以通過實例或類進行調用。同時,類方法還可以用於在類實例化之前對類進行一些處理。
1 class Foo: 2 num = 1 3 4 @classmethod 5 def instance(cls): 6 cls.num = 7 7 cls = cls() 8 return cls 9 10 def__init__(self): 11 self.foo = Foo.num 12 13 def test(self): 14 print(‘This is a test‘) 15 16 cls_1 = Foo() 17 print("foo is: %d, num is: %d" % (cls_1.foo, cls_1.num)) 18 19 # Change num from 1 to 7 before __init__ 20 cls_2 = Foo.instance() 21 print("foo is: %d, num is: %d" % (cls_2.foo, cls_2.num)) 22 cls_2.test()
上面的代碼中,定義了一個類方法,這個類方法會在調用的時候修改 Foo 類的 num 屬性,隨後在生成一個類實例(第 7 行,這步實際上完成了一個類的初始化)並返回。首先不調用類方法,直接生成一個類實例 cls_1,隨後查看 cls_1 中的屬性值,然後在利用類方法,通過 Foo 直接調用 instance 方法生成一個類實例 cls_2,並同樣的查看類實例中的屬性,最後調用 test 方法來測試這個類實例是否可以和正常生成的類實例一樣調用實例方法。
foo is: 1, num is: 1 foo is: 7, num is: 7 This is a test
最後的輸出結果可以看出,直接生成的類實例 cls_1 中的屬性並沒有被改變,而通過類實例方法生成的類實例 cls_2 中的屬性則變化了,同時這個 cls_2 也同樣能夠調用普通的實例方法。也就是說類方法可以通過類進行直接調用而不需要先經過實例化,同時類方法傳入的第一個參數 cls 即為當前的類。
Note: 這種類方法可以用在單例模式(參考單例模式)中,確保一個類無論實例化多少次都只有一個實例對象存在。
屬性方法 / Property Method
在 def 定義之前加上 @property 進行裝飾,使得該方法成為屬性方法,屬性方法可以在外部像調用屬性一樣直接進行調用,若需要實現對屬性方法值的修改,則還需要定義由 @methodname.setter 裝飾的同名方法,在這個方法內實現對屬性方法返回值的修改。
1 class Foo(object): 2 3 def __init__(self): 4 self._foo = None 5 6 @property 7 def foo(self): 8 return self._foo 9 10 @foo.setter 11 def foo(self, value): 12 if isinstance(value, int): 13 self._foo = (value + 0.5) 14 15 if __name__ == "__main__": 16 f = Foo() 17 print("foo is %s" % f.foo) 18 f.foo = 1 19 print("foo is %s" % f.foo)
上面的代碼中定義了一個 foo 的屬性方法和屬性方法的 setter,這樣就是的 foo 這個方法使用起來就如同是一個屬性一般,可以直接通過實例進行調用(第17 / 19 行),而 @foo.setter 裝飾器也賦予了 foo 屬性方法賦值的能力,可以通過類似屬性賦值的方式直接給 foo 傳遞一個參數(第 18 行),並且此時還可以對這個傳入的參數進行一定的操作(如第 12 / 13 行)。
foo is None foo is 1.5
最終輸出的結果中可以看出,foo 雖然是一個方法,但是其使用的方式卻完全類似於一個屬性,這中屬性方法所提供的功能在面向對象編程的時候十分有效,常常可以通過定義好屬性方法來實現一系列對象的操作,使得一個實例更加接近真實對象的行為方式(上面的例子可能不算十分恰當,不過可以理解為一個識別器,只要傳入的是數字,便修改自身的 _foo 屬性為該值+0.5,而在外部則無需關心這一實現,只把 foo 當做是一個屬性賦值即可)。
Python的程序結構(2) -> 方法/Method -> 靜態方法、類方法和屬性方法