Python,你真的會(huì)使用 staticmethod 和 classmethod 嗎?
點(diǎn)擊上方“AirPython”,選擇“加為星標(biāo)”
第一時(shí)間關(guān)注 Python 技術(shù)干貨!

1. 場(chǎng)景
前幾天,有一個(gè)小伙伴過(guò)來(lái)問(wèn)我,Python 中的 @staticmethod、@classmethod、self、cls 分別代表什么意思,自己平時(shí)光顧著用,不知道具體的含義?
事實(shí)上,由于 Python 語(yǔ)言的靈活性,這部分內(nèi)容在日常編碼過(guò)程中,很容易被忽略掉
本篇文章將和大家一起聊聊這幾個(gè)小知識(shí)點(diǎn)
2.@staticmethod
裝飾器 @staticmethod 修飾的方法稱為:靜態(tài)方法,和普通的函數(shù)沒(méi)有什么區(qū)別
下面將聊聊實(shí)際項(xiàng)目中幾種應(yīng)用場(chǎng)景
1、要調(diào)用一個(gè)靜態(tài)方法,一般使用形式是:「 類名.方法名()?」
class?Web(object):
????@staticmethod
????def?foo_staticmethod():
????????"""靜態(tài)方法"""
????????pass
if?__name__?==?'__main__':
????#?直接使用類名+方法名調(diào)用
????Web.foo_staticmethod()
當(dāng)然,也可以實(shí)例化一個(gè)類對(duì)象,通過(guò)這個(gè)對(duì)象去調(diào)用靜態(tài)方法,但是不建議使用這種方式
#?實(shí)例化一個(gè)對(duì)象
instance?=?Web()
#?使用實(shí)例對(duì)象去調(diào)用靜態(tài)方法(不建議)
instance.foo_staticmethod()??2、針對(duì)類中定義的靜態(tài)變量,可以使用「?類名.變量名?」?的形式去訪問(wèn)
class?Web(object):
????#?靜態(tài)變量(類變量)
????name?=?"Python_Web"
????@staticmethod
????def?foo_staticmethod():
????????"""靜態(tài)方法"""
????????#?引用靜態(tài)變量
????????print(Web.name)?
3、靜態(tài)方法內(nèi)部使用其他靜態(tài)方法、類方法,同樣是使用「?類名.方法名()?」去調(diào)用
class?Web(object):
????#?靜態(tài)變量(類變量)
????name?=?"Python_Web"
????#?類方法
????@classmethod
????def?foo_classmethod_other(cls):
????????print('類方法被調(diào)用!')
????#?另外一個(gè)靜態(tài)方法
????@staticmethod
????def?foo_staticmethod_other():
????????print('另外一個(gè)靜態(tài)方法被調(diào)用!')
????@staticmethod
????def?foo_staticmethod():
????????"""靜態(tài)方法"""
????????#?調(diào)用其他靜態(tài)方法
????????print(Web.foo_staticmethod_other())?
????????#?調(diào)用類方法
????????print(Web.foo_classmethod_other())
4、靜態(tài)方法內(nèi)部調(diào)用普通方法,訪問(wèn)實(shí)例屬性
普通方法和實(shí)例屬性都必須通過(guò)實(shí)例對(duì)象去引用,不能直接使用類名去訪問(wèn)
class?Web(object):
????def?__init__(self):
????????self.desc?=?"實(shí)例屬性,不共享"
????def?norm_method(self):
????????"""普通方法"""
????????print('普通方法被調(diào)用!')
????@staticmethod
????def?foo_staticmethod():
????????"""靜態(tài)方法"""
????????instance?=?Web()
????????#?獲取實(shí)例屬性
????????print(instance.desc)
????????#?調(diào)用普通方法
????????instance.norm_method()
5、子類的使用
在子類中調(diào)用父類定義好的靜態(tài)方法,只需要將類名替換為子類名稱即可
class?Web(object):
????@staticmethod
????def?foo_staticmethod(arg1,?arg2):
????????pass
class?Django(Web):
????"""子類"""
????pass
if?__name__?==?'__main__':
????#?1、使用類名(父類)去調(diào)用靜態(tài)方法
????Web.foo_staticmethod("Hello",?",AirPython")
????#?2、使用類名(子類)去調(diào)用靜態(tài)方法
????Django.foo_staticmethod("Hello",?",AirPython")
3.@classmethod
裝飾器 @classmethod 修飾的方法稱為:類方法,在使用的時(shí)候,會(huì)將類本身作為第一個(gè)參數(shù) cls 傳遞給類方法
#?類方法,第一個(gè)參數(shù)為cls,代表類本身
@classmethod
def?foo_classmethod(cls):
????pass
其中,cls?代表外層類本身,可以實(shí)例化,也可以直接調(diào)用靜態(tài)方法、類方法、靜態(tài)變量
下面逐一進(jìn)行說(shuō)明
1、要調(diào)用一個(gè)類方法,一般使用形式是:「?類名.方法名()?」
class?Web(object):
????#?類方法,第一個(gè)參數(shù)為cls,代表類本身
????@classmethod
????def?foo_classmethod(cls):
????????pass
if?__name__?==?'__main__':
????#?使用類名去調(diào)用類方法
????Web.foo_classmethod()
和靜態(tài)方法類似,也可以實(shí)例化一個(gè)類對(duì)象,通過(guò)這個(gè)對(duì)象去調(diào)用靜態(tài)方法,但是不建議使用這種方式
2、調(diào)用靜態(tài)變量
靜態(tài)方法內(nèi)部引用靜態(tài)變量有兩種方式,分別是:
「?類名.變量名?」
「 cls.變量名?」
注意:由于 cls 代表就是外層類本身,所以這兩種方式等效
class?Web(object):
????#?靜態(tài)變量(類變量)
????name?=?"Python_Web"
????#?類方法,第一個(gè)參數(shù)為cls,代表類本身
????@classmethod
????def?foo_classmethod(cls):
????????#?調(diào)用靜態(tài)變量方式一
????????print(cls.name)
????????#?調(diào)用靜態(tài)變量方式二
????????print(Web.name)3、類方法內(nèi)部調(diào)用其他類方法、靜態(tài)方法
在一個(gè)類方法內(nèi)部,可以使用「?類名.類方法名()?」、「?類名.靜態(tài)方法名()?」的形式去調(diào)用方法
class?Web(object):
????#?靜態(tài)方法
????@staticmethod
????def?foo_staticmethod():
????????print('靜態(tài)方法被調(diào)用!')
????#?其他類方法
????@classmethod
????def?foo_classmethod_other(cls):
????????print('另外一個(gè)類方法被調(diào)用!')
????#?類方法,第一個(gè)參數(shù)為cls,代表類本身
????@classmethod
????def?foo_classmethod(cls):
????????#?調(diào)用其他類方法
????????cls.foo_classmethod_other()
????????#?調(diào)用靜態(tài)方法
????????cls.foo_staticmethod()
if?__name__?==?'__main__':
????Web.foo_classmethod()
4、類方法內(nèi)部調(diào)用普通方法,訪問(wèn)實(shí)例屬性
需要通過(guò) cls?變量實(shí)例化一個(gè)類對(duì)象,然后通過(guò)這個(gè)對(duì)象去調(diào)用普通方法和實(shí)例屬性
class?Web(object):
????def?__init__(self):
????????self.desc?=?"實(shí)例屬性,不共享"
????def?norm_method(self):
????????"""普通方法"""
????????print('普通方法被調(diào)用!')
????#?類方法,第一個(gè)參數(shù)為cls,代表類本身
????@classmethod
????def?foo_classmethod(cls):
????????#?如果要調(diào)用實(shí)例屬性,必須使用cls實(shí)例化一個(gè)對(duì)象,然后再去引用
????????print(cls().desc)
????????#?如果要調(diào)用普通方法,必須使用cls實(shí)例化一個(gè)對(duì)象,然后再去引用
????????cls().norm_method()5、子類的使用
在子類中調(diào)用父類定義好的類方法,只需要將類名替換為子類名稱即可,代碼和靜態(tài)方法類似
4.區(qū)別
下面總結(jié)一下普通方法、靜態(tài)方法、類方法的區(qū)別
普通方法:第一個(gè)參數(shù) self 代表實(shí)例對(duì)象本身,可以使用 self 直接引用定義的實(shí)例屬性和普通方法;如果需要調(diào)用靜態(tài)方法和類方法,通過(guò)「?類名.方法名()?」調(diào)用即可
靜態(tài)方法:使用「?類名.靜態(tài)變量?」引用靜態(tài)變量,利用「?類名.方法名()?」調(diào)用其他靜態(tài)方法和類方法;如果需要調(diào)用普通方法,需要先實(shí)例化一個(gè)對(duì)象,然后利用對(duì)象去調(diào)用普通方法
類方法:第一個(gè)參數(shù) cls 代表類本身(等價(jià)),通過(guò)「 cls.靜態(tài)變量?」或「 類名.靜態(tài)變量?」引用靜態(tài)變量,利用「?cls.方法名()?」或「 類名.方法名()?」去調(diào)用靜態(tài)方法和類方法;如果需要調(diào)用普通方法,需要先實(shí)例化一個(gè)對(duì)象,然后利用對(duì)象去調(diào)用普通方法
靜態(tài)方法和類方法是針對(duì)類定義的,除了可以使用類名去調(diào)用,也可以使用實(shí)例對(duì)象去調(diào)用,但是不建議
5.最后
一般來(lái)說(shuō),如果方法內(nèi)部涉及到實(shí)例對(duì)象屬性的操作,建議用普通方法;如果方法內(nèi)部沒(méi)有操作實(shí)例屬性的操作,僅僅包含一些工具性的操作,建議使用靜態(tài)方法;而如果需要對(duì)類屬性,即靜態(tài)變量進(jìn)行限制性操作,則建議使用類方法
我已經(jīng)將文中全部源碼上傳到后臺(tái),關(guān)注公眾號(hào)后回復(fù)「 pmethod?」即可獲得全部源碼
如果你覺得文章還不錯(cuò),請(qǐng)大家?點(diǎn)贊、分享、留言?下,因?yàn)檫@將是我持續(xù)輸出更多優(yōu)質(zhì)文章的最強(qiáng)動(dòng)力!
