先給大家拜年,新年第一篇繼續我複習面向對象的知識,這次打算說說我疑惑挺久的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<< span="">class '__main__.Person'>,hello,earthman<< span="">class '__main__.Person'>,hello,earthmanhello,earthman可以看到使用了classmethod或者staticmethod裝飾後的方法,調用有些不一樣,可以直接用類名.方法名()調用。
一開始我並沒有get到這種做法有什麼特別妙的地方,看了眾多大佬的解讀,總結出:
•減少實例化對象的開銷,如果方法沒有用到實例化的任何屬性和方法,推薦使用靜態類方法@staticmethod
•屬於類的方法放到類裡面,利於組織代碼,容易閱讀。
cls和self有什麼特點
類的方法,第一個參數必須是self或者是cls(必須用classmethod裝飾),這是一種約定。
cls,表示的是類本身,self表示實例化具體對象的本身。好比說在解析器執行代碼的時候,具體的Person類也是一個對象,cls是Person的引用。slef就是lm對象的引用。
第一個參數為什麼必須是cls或者self?將在下面最後講到。
staticmethod和classmethod的特點
上面說到使用了這兩者裝飾的方法都可以用類.方法()調用,這兩個有什麼特點?
•@staticmethod,不需要self或者cls參數,靜態方法,主要處理與這個類的邏輯關聯, 如驗證數據。注意,無法在靜態類方法中使用實例化屬性或者方法,比如上面的靜態類方法:
@staticmethoddef 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傳遞類對象進行調用。在重構的時候,也用得著。
以上就是本次閱讀了大量資料後整理出的資料,希望對你們有幫助。