文章首發於 微信公衆號:Python編程時光編程
這個標題「靜態方法其實暗藏玄機」其實只是該文章的一個知識點。或許有些標題黨,但沒有關係,我相信有很多人對此並無深刻研究他們,不信我問你三個問題,你看可否答上來。微信
一、Python2.x和3.x中,函數和方法的區分有什麼不一樣?函數
二、有了類/實例方法和普通函數,爲何還會有靜態方法?工具
三、Python3.x 中,靜態方法有幾種寫法?測試
帶着這三個問題,你能夠嘗試在下文中尋找答案。設計
在 Python 2 中的函數和方法的區別,十分清晰,很好分辨。但在 Python3中,我卻發現徹底又是另外一套準則。3d
首先先來 Python2 的(如下在 Python2.7中測試經過)code
能夠得出結論:cdn
一、普通函數(未定位在類裏),都是函數。對象
二、靜態方法(@staticmethod),都是函數。
三、類方法(@classmethod),都是方法。
四、實例方法(首參數爲self且非靜態、非類方法的),都是方法。
你必定想說,類方法和實例方法,是方法沒錯呀,畢竟名字自己就有方法,普通函數是函數,我也理解呀。那靜態方法,爲何不是方法而是函數呢?
名字只是一個外在的表面稱呼,你能說「趙鐵男」就必定是漢子嗎?
個人理解是:方法是一種和對象(實例或者類)綁定後的函數。
類方法的首參是cls
,調用時,無需顯示傳入。實例方法首參是self,調用時,也無需顯示傳入。
而靜態方法,其實和普通函數沒啥區別,惟一的區別就是,他定義的位置被放在了類裏,作爲類或者實例的一個函數。
那你確定又要問了,既然靜態方法和普通函數都是同樣的,爲何要刻意將它放在類裏呢?
我上面說了,放在類裏定義,就可讓它成爲類的一個工具函數,這就像你身上隨身攜帶了一把刀,這把刀與你本人並無什麼直接關係,惟一的聯繫就是這把刀是你的,而你把它帶在身上,不管你去到哪裏,只要須要,你就能夠直接拿出來用上。對比將函數放在類外面,缺點是什麼呢?就是當你出門在外(在別的模塊裏)發現你要用刀的時候,還要特意跑一趟去商店買一把刀(import 這個函數)。
另外,我以爲靜態方法在業務和設計上的意義,會更多一些。
通常靜態方法是作爲類或者實例的一個工具函數,好比對變量的作一個合法性的檢驗,對數據進行序列化反序列化操做等等。
說完了 Python2 ,再來講說Python3.
之前我以爲 Python2 對於方法和函數的界線更加清晰,但接觸了 Python3,我反而以爲Python3裏方法和函數的區分彷佛更加合理。
仍是剛剛那段代碼,我更改了解釋器爲Python3.6(如下在 Python3.6中測試經過)
和Python2的惟一區別是,People.jump
在Python3 中變成了函數。
這一下顛覆了你剛剛纔創建起來的知識體系有木有?
先別急,我再作個試驗,也許你就知道了。
在 Python2中
執行People.jump('hello'),會報錯說,jump的首參必須爲People的實例對象,這能夠理解,畢竟jump定義時,第一個參數爲self。
在 Python3中
你能夠發現,這裏的jump的首參再也不要求是 People 的一個實例,而能夠是任意的對象,好比我使用字符串對象,也沒有報錯。
也就是說,當你往jump中傳入的首參爲People的實例時,jump 就是方法,而當你傳入的首參不是People的實例對象時,jump就是函數。
你看,多麼靈活呀。
再總結一下,在Python3中:
一、普通函數(未定位在類裏),都是函數。
二、靜態方法(@staticmethod),都是函數。
三、類方法(@classmethod),都是方法。
四、方法和函數區分沒有那麼明確,而是更加靈活了,一個函數有多是方法也有多是函數。
你確定又要問了,那這是否是就意味着,Python3 中靜態方法,能夠不用再使用@staticmethod 裝飾了呢,反正Python3均可以識別。
這是個好問題,是的,能夠不用指定,可是最好指定,若是你不指定,你調用這個方法只能經過People.jump,而不能經過 self.jump了,由於首參不是 self,而若是使用@staticmethod 就可使用self.jump。
因此說這是一個規範,就像類的私有方法,規範要求外部最好不要調用,但這不是強制要求,不是說外部就不能調用。
寫這篇文章的起源,是前兩天有位讀者在交流裏問到了相關的問題,正好沒什麼主題能夠寫,就拿過來作爲素材整理一下,也正好沒有寫過靜態方法、類方法的內容,沒想到簡單的東西,也能寫出這麼多的內容出來。