先給大家拜年,新年第一篇繼續我複習面向物件的知識,這次打算說說我疑惑挺久的self,cls,staticmethod,classmethod是幹嘛的,有什麼用。
這裡會說到:類方法,靜態方法,類屬性,例項方法等相關。先看一個例子:
class Person: belong_to = 'earthman' def __init__(self,skin, name): self.skin = skin self.name = name def get_skin(self): return self.skin @classmethod def menthod_cls(cls): print(f'{cls},hello,{Person.belong_to}') @staticmethod def menthod_state(): print(f'hello,{Person.belong_to}') lm = Person('yellow', '李明') print(lm.get_skin()) print(Person.menthod_cls()) print(lm.menthod_cls()) print(Person.menthod_state()) #輸出 yellow <class '__main__.Person'>,hello,earthman <class '__main__.Person'>,hello,earthman hello,earthman
可以看到使用了classmethod或者staticmethod裝飾後的方法,呼叫有些不一樣,可以直接用類名.方法名()呼叫。
一開始我並沒有get到這種做法有什麼特別妙的地方,看了眾多大佬的解讀,總結出:
減少例項化物件的開銷,如果方法沒有用到例項化的任何屬性和方法,推薦使用靜態類方法@staticmethod屬於類的方法放到類裡面,利於組織程式碼,容易閱讀。cls和self有什麼特點類的方法,第一個引數必須是self或者是cls(必須用classmethod裝飾),這是一種約定。
cls,表示的是類本身,self表示例項化具體物件的本身。好比說在解析器執行程式碼的時候,具體的Person類也是一個物件,cls是Person的引用。slef就是lm物件的引用。
第一個引數為什麼必須是cls或者self?將在下面最後講到。
staticmethod和classmethod的特點上面說到使用了這兩者裝飾的方法都可以用類.方法()呼叫,這兩個有什麼特點?
@staticmethod,不需要self或者cls引數,靜態方法,主要處理與這個類的邏輯關聯, 如驗證資料。注意,無法在靜態類方法中使用例項化屬性或者方法,比如上面的靜態類方法:@staticmethod def menthod_state(): print(f'hello,{Person.belong_to}') print(Person.get_skin())
以上使用了例項化self物件的方法會報錯。我的理解是,帶有self的方法,是例項化物件的方法,所以無法透過類物件來使用。@classmethod,第一個引數必須是cls,類方法,可以來呼叫類的屬性,類的方法,例項化物件等,避免硬編碼。比如上面使用類.方法(),例項化.方法()效果是一樣的。重構類的時候不必要修改建構函式,只需要額外新增你要處理的函式(使用場景)。我在看scrapy程式碼中發現不少這型別的方法,現在想來確實是用在重構中多些,之前還看不懂。為什麼必須在方法定義和呼叫中顯式使用“self”?據說曾經有建議取消self,後來被python發明的大佬回答為什麼必須帶self的原因。首先self代表了例項化物件。比如:
lm = Person('yellow', '李明') lm.get_skin()#類成員方法 #也可以這樣使用,一樣能用 Person.get_skin(lm)
lm現在是一個具體叫李明的人,那麼在呼叫Person成員方法的時候,會隱式傳遞lm物件給get_skin(),也就是self。那為什麼非要把self寫到方法中?在官方python文件有解釋:
在python中沒有區域性變數宣告,加self就可以表示本例項化的變數/方法。可以理解成類裡面的全域性變數,區域性變數和例項變數存在於兩個不同的名稱空間中,您需要告訴 Python 使用哪個名稱空間。
那麼對於cls引數其實也類似,必須告訴呼叫的方法,具體的類名,透過cls傳遞類物件進行呼叫。在重構的時候,也用得著。