我們繼續(xù)講解Python裝飾器。上一講我們把裝飾器的基本原理講了毅戈,這一講我們來談?wù)勓b飾器相關(guān)的語法。
1. @是語法糖
下面這兩段代碼是等效的,與其讓decorator顯式接收一個func作為參數(shù)敦第,然后將調(diào)用后得到的結(jié)果賦值給func變量,我們可以直接在定義的func前加上@decorator
語句也能達到相同的效果店量,而且更方便芜果。我們把這個@語句稱為語法糖。
所謂語法糖可以理解成是實現(xiàn)特定功能的捷徑融师,它簡化了我們編寫代碼的方式右钾。這里的@語句在定義函數(shù)時使用,使代碼更容易閱讀并且可以立即意識到應(yīng)用了裝飾器。值得一提的是舀射,在Python中語法糖是大量存在的窘茁,而不僅僅是局限于裝飾器中。
簡單一點的脆烟,假如我們要構(gòu)建一個列表山林,此時的[1,2,3]
相對于list(1,2,3)
就是語法糖。復(fù)雜一點的邢羔,假如我們要創(chuàng)建一個迭代器驼抹,寫一個生成器函數(shù)相對于直接構(gòu)造一個迭代器的類就是一種語法糖,而寫一個生成器表達式則是相比于生成器函數(shù)更進一步的語法糖拜鹤。
2. 裝飾器在被裝飾的函數(shù)定義后立即運行
理解裝飾器在何時運行的問題是我們理解被裝飾過的函數(shù)的種種行為的基礎(chǔ)框冀。
可以看到,裝飾器函數(shù)在自身和被裝飾函數(shù)定義完成后敏簿,會立即被調(diào)用明也,也就是說裝飾器在被加載到模塊后會立即運行。而裝飾后的函數(shù)f极谊,只有顯式調(diào)用才會被執(zhí)行诡右。那么原函數(shù)呢?這里原函數(shù)和被裝飾后的函數(shù)是同一個轻猖,更常見的情況是被裝飾后的函數(shù)包含對原函數(shù)的引用帆吻,顯式調(diào)用被裝飾后的函數(shù)也會順帶調(diào)用原函數(shù)。
3. 對一個函數(shù)應(yīng)用多個裝飾器
對一個函數(shù)應(yīng)用多個裝飾器從整體上來理解就是對裝飾后得到的被裝飾函數(shù)再進行裝飾咙边。
多個裝飾器也不限于兩個猜煮,也可以多次使用同一個裝飾器
下面把整段代碼貼出來和大家一起分析下
這段代碼中有以下幾點值得注意:
- 這里面的
f
、warpper1
败许、warpper2
都是使用相同的位置參數(shù)王带,這一點很重要,是確保裝飾器能正確運行的前提市殷。 - 這個裝飾的過程是自里向外的愕撰,我們先裝飾
f
得到wrapper1
,再裝飾wrapper1
得到warpper2
醋寝。
注意到以上兩點后我們再來看裝飾后的f
的運行情況搞挣。當(dāng)我們調(diào)用f("haha")
時,其實相當(dāng)于運行warpper2("haha")
音羞,warpper2
在運行時又會調(diào)用warpper1
囱桨,并把從位置參數(shù)text接收來的變量值"haha"傳給wrapper1
,wrapper1
在運行時又會調(diào)用真正的f
嗅绰,然后也把從位置參數(shù)text接收來的變量值"haha"傳給f
舍肠,最后f
運行完成搀继,又返回到wrapper1
,wapper1
運行完成返回到wrapper2
翠语,wrapper2
運行完成這個函數(shù)才算結(jié)束叽躯。
4. *args, **kwargs
通常我們在定義裝飾器時,為了裝飾器能更加的通用肌括,需要考慮到被裝飾的函數(shù)參數(shù)個數(shù)不一致的問題险毁。就比如上面定義的的那個裝飾器,它要求被裝飾的函數(shù)只能有一個參數(shù)们童,因為我們后續(xù)調(diào)用時,只能給被裝飾后的函數(shù)wrapper
一個參數(shù)鲸鹦。而wrapper
恰恰是代替原函數(shù)f
接受調(diào)用的慧库。
知道了問題所在,我們讓wrapper接受可變的參數(shù)個數(shù)也就解決問題了馋嗜。