1. 程式人生 > >python的staticmethod,classmethod和裝飾器以及閉包的愛恨情仇

python的staticmethod,classmethod和裝飾器以及閉包的愛恨情仇

經常都是你去面試,面試官一臉冷漠,聽說你會Python,那給你30秒,寫一個裝飾器,應該很簡單吧?然後你一臉矇蔽,裝飾器大家都聽過,我們也大致知道什麼意思,但是讓寫一個,你會寫嗎?

我們在python的程式中,經常看到一些類中,一些函式定義前面,寫有@staticmethod,@classmethod等東東,這些是什麼鬼呢?且聽我細細道來,先來解釋一下staticmethod和classmethod。直接一點來說,我們知道對於一個普通的類,我們要使用其中的函式的話,需要對類進行例項化,而一個類中,某個函式前面加上了staticmethod或者classmethod的話,那麼這個函式就可以不通過例項化直接呼叫,什麼意思呢?就是說有時候,我們需要把一些具有特定功能的函式放到一起,做成包匯入Python程式,最好就是把他們放到一個類中,但是一個類每次我都要去例項化他,我覺得很麻煩,於是我在函式前面加上了@staticmethod,@classmethod,那麼我下次用這個函式的功能的時候,可以直接用 類名.函式名

的形式了,這樣是不是省心多了?

我相信到這裡應該把這兩個東東大致的功能講清楚了,但是,這兩個方法本身有什麼區別呢?

  • @staticmethod不需要表示自身物件的self和自身類的cls引數,就跟使用函式一樣。
  • @classmethod也不需要self引數,但第一個引數需要是表示自身類的cls引數。
  • 如果在@staticmethod中要呼叫到這個類的一些屬性方法,只能直接類名.屬性名或類名.方法名。
  • @classmethod因為持有cls引數,可以來呼叫類的屬性,類的方法,例項化物件等,避免硬編碼。

簡單來說,就是staticmethod不需要傳入表示自身物件引數,而classmethod需要傳入一個類似於self的cls引數。那麼既然classmethod麻煩一點,必然有他麻煩的道理,就是:使用classmethod的話,凡是在該類中的類的屬性,方法,例項化物件等,都可以調用出來。

那麼說了這麼久,staticmethod和classmethod方法本質上是一個什麼東西,好像樓主你並沒有說清楚啊?

不錯,大家看staticmethod和classmethod前面都有一個@符號,我們知道在微信qq裡面,要@一個人,必然是有求於他。在這裡也是一樣的,我們的@xxx這樣的形式,表示一個裝逼器,哦對不起,說錯了,是裝飾器。那麼這個裝飾器又是何方神聖呢?

簡而言之,有時候我們覺得這個函式不夠完善,我想在這個函式的基礎上拓展一些額外的通用的功能,但是由於這個函式又很重要,不能直接侵入程式碼去改,加上可能其它的函式也需要這樣一種功能,那麼我們就需要用到裝逼器了,就是這樣一個@xxx的東西。

一個簡單的例子,我們要實現一個對函式執行時間計時的功能,因為我們依稀記得老師說過:一切皆物件。那麼我們最簡單粗暴的方法當然是,把這個函式當成一個引數,傳入另外一個計時函式中,bingo。

但是,如果老闆說現在有一千萬個函式,都需要這樣一個功能呢?好像這個方法不太體面,有沒有裝B一點的方法呢,當然,就是這個裝飾器。

下面寫一個最簡單的裝飾器,在原函式中不需要傳入任何的引數的形式,記住,一定要返回函式。

當原函式中含有引數,怎麼辦呢,於是我們還可以寫含有引數的裝飾器:

但是這個問題在於也太過於定製化了,什麼意思呢,就是說我們並不能保證每個函式都恰好具有兩個引數,當有多個引數的時候,我希望這個裝飾器同樣可以用,那麼就需要用到這裡的 多引數裝飾器。

## 多引數的時候,複習一下多引數傳入的方式:

**kwargs:(表示的就是形參中按照關鍵字傳值把多餘的傳值以字典的方式呈現)。

位置引數、*args**kwargs三者的順序必須是位置引數、*args**kwargs,不然就會報錯。

言歸正傳,再說這邊:對於一些函式如果都需要這樣的裝飾器,但是這個函式的引數數量各不相同,那麼就需要向下面這樣:

那麼苛刻的老闆又跳出來,這樣一個裝飾器不能滿足我的要求,我想要多個裝飾器。

好的,你一下@出來了多個大佬,這些大佬的出場順序呢,搞不好的話大佬會互相砍起來。

簡單一個圖就可以把人看暈,噢不對,看懂。考驗智商的時候到了同志們。

張無忌,你懂了嗎,你真的懂了嗎,好的,那你看看下面的程式,應該輸出什麼內容(答案如箭頭所示):

有人說,我怎麼感覺這個東西和閉包有著藕斷絲連的、牽扯不清的情感糾葛?

閉包是什麼?於是又引入閉包的含義,閉包:簡而言之,在函式內部對外部作用域的區域性變數x進行引用,但是一通騷操作之後並不會影響區域性變數x的值。見下圖:

注意:閉包中是不能修改外部作用域的區域性變數。

請看下面的一個程式,很多人沒搞清楚的時候會以為結果是2,3,4,但是不是。

要實現原來的234的功能也很簡單,只需要動動手腳:

你問閉包這個脫褲子放屁的功能有什麼用呢,還真有用,比如有時候我們希望在函式內部,在實現其他的函式的時候,環境的值不改變,而只是呼叫這個值;另外閉包可以根據外部作用域的區域性變數,得到不同的結果,類似於配置不同的功能。

談了這麼多,我們可以簡而言之理解一下@staticmethod了,這就相當於是一個裝飾器,當然這個裝飾器比我們的對函式計時等helloworld級別的裝飾器牛逼閃閃多了,這個裝飾器作用在這個函式上,使得該函式很牛逼,然後告訴我們,你不用例項化了,你直接用吧。

好了,生活就是這麼有趣,Python也是,當你試圖搞懂一個staticmethod的時候,你得搞懂裝飾器,要搞懂裝飾器,你還要知道閉包,要知道閉包,你還要看懂這篇博文。。。