靜態方法是指類中無需實例參與即可調用的方法(不需要self參數),在調用過程中,無需將類實例化,直接在類之后使用.號運算符調用方法。
通常情況下,靜態方法使用@staticmethod裝飾器來聲明。
示例代碼:
class ClassA(object): @staticmethod def func_a(): print('Hello Python') if __name__ == '__main__': ClassA.func_a() # 也可以使用實例調用,但是不會將實例作為參數傳入靜態方法 ca = ClassA() ca.func_a()
這里需要注意的是,在Python 2 中,如果一個類的方法不需要self參數,必須聲明為靜態方法,即加上@staticmethod裝飾器,從而不帶實例調用它。
而在Python 3中,如果一個類的方法不需要self參數,不再需要聲明為靜態方法,但是這樣的話只能通過類去調用這個方法,如果使用實例調用這個方法會引發異常。
class ClassA(object): def func_a(): print('Hello Python') if __name__ == '__main__': ClassA.func_a() # 以下使用實例調用會引發異常 ca = ClassA() ca.func_a()
異常信息:
func_a() takes 0 positional arguments but 1 was given
因為func_a沒有聲明為靜態方法,類實例在調用func_a時,會隱式地將self參數傳入func_a,而func_a本身不接受任何參數,從而引發異常。
類方法在Python中使用比較少,類方法傳入的第一個參數為cls,是類本身。並且,類方法可以通過類直接調用,或通過實例直接調用。但無論哪種調用方式,最左側傳入的參數一定是類本身。
通常情況下,類方法使用@classmethod裝飾器來聲明
class ClassA(object): @classmethod def func_a(cls): print(type(cls), cls) if __name__ == '__main__': ClassA.func_a() ca = ClassA() ca.func_a()
從運行結果可以看出,無論是類調用還是實例調用,類方法都能正常工作。且通過打印cls,可以看出cls傳入的都是類實例本身。
<class 'type'> <class '__main__.ClassA'> <class 'type'> <class '__main__.ClassA'>
這里需要注意,如果存在類的繼承,那類方法獲取的類是類樹上最底層的類。
class BaseA(object): @classmethod def func_a(cls): print(type(cls), cls) class BaseB(object): pass class ClassA(BaseA, BaseB): pass if __name__ == '__main__': ClassA.func_a() ca = ClassA() ca.func_a()
代碼中ClassA繼承自BaseA、BaseB,在調用類方法時,雖然類方法是從BaseA繼承而來,但是傳入func_a的cls函數實際上是ClassA,也就是最底層(最具體)的類。
運行結果:
<class 'type'> <class '__main__.ClassA'> <class 'type'> <class '__main__.ClassA'>
所以,在某些時候,需要明確調用類屬性時,不要使用類方法傳入的cls參數,因為它傳入的是類樹中最底層的類,不一定符合設計初衷。
可以直接通過類名訪問類屬性。
class BaseA(object): @classmethod def func_a(cls):
# 直接使用類名,而不使用cls print(BaseA) print(type(cls), cls) class BaseB(object): pass class ClassA(BaseA, BaseB): pass if __name__ == '__main__': ClassA.func_a()
實例方法,除靜態方法與類方法外,類的其他方法都屬於實例方法。
實例方法需要將類實例化后調用,如果使用類直接調用實例方法,需要顯式地將實例作為參數傳入。
最左側傳入的參數self,是實例本身。
class ClassA(object): def func_a(self): print('Hello Python') if __name__ == '__main__': # 使用實例調用實例方法 ca = ClassA() ca.func_a() # 如果使用類直接調用實例方法,需要顯式地將實例作為參數傳入 ClassA.func_a(ca)