Python裝飾器演化過程
Python 的裝飾器可能是很多初學者難以搞懂的知識點之一,其實以前我也有講解這方面的知識,不過那是在 pandas 專欄里面。
今天以另一個角度再次講解裝飾器。
場景
先看看一開始的代碼:
- 行2:這是今天我們需要實現(xiàn)的裝飾器函數(shù)
- 行5:裝飾器函數(shù)可以作用到任意其他的函數(shù)上
- 行10:每當調用被裝飾的函數(shù),就會在執(zhí)行函數(shù)之前打印一句內容,運行結束后,打印結果內容
比如 行10 執(zhí)行后,后臺會輸出。
接下來,我們一步步實現(xiàn) faker 函數(shù)。
函數(shù)名字是變量名而已
前面定義的函數(shù) mysum ,只不過是一個普通變量。就像你用一個變量保存了一個字符串一樣:
mystr = 'xxxx'
只不過函數(shù)是表達一段代碼(邏輯)。怎么證明?
python 中可以用 del 關鍵字刪除一個變量:
行12 會報錯:
NameError: name 'mysum' is not defined
不怕,可以先用另一個變量"接住"函數(shù)對象:
行8:注意了,mysum 后面沒有帶括號。因為函數(shù)名 + 括號,才是執(zhí)行函數(shù)體內的代碼。只是寫函數(shù)名字,實際上并沒有執(zhí)行函數(shù)。
好了,到此為止,下面是初始版本的 faker:
非常簡單了,應該大家都能理解。不過現(xiàn)在 faker 一點都不像 mysum 呀!調用是這樣子的:
而且參數(shù) 1 和 2 還固定寫在了 faker 里面。
那么,先解決參數(shù)的問題吧,非常簡單,設置兩個參數(shù)就可以:
用上一開始的"變量假冒法" :
但 faker 函數(shù)里面仍然有一個固定的東西(行8),那個 other_func 變量永遠指向 mysum 函數(shù)(行4)。我們希望 faker 函數(shù)可以假冒任意的函數(shù)。
函數(shù)傳遞
我們既然學會了"變量假冒法",那么就能知道,函數(shù)對象其實與普通的數(shù)據(jù)差不多,是可以通過參數(shù)傳入另一個函數(shù)中。
- 行6:新增一個參數(shù),讓外面把 mysum 傳進來吧,這樣子就變動態(tài)了
- 行12:傳入 mysum 函數(shù)。注意,mysum 后面是沒有括號,我們沒有執(zhí)行 mysum 函數(shù)本身
但是顯然,現(xiàn)在代碼報錯了,因為 faker 函數(shù)原來的兩個變量 a 和 b 沒有了。就算把 a 和 b 加上,也不行:
我們并不是要在行12那里執(zhí)行函數(shù)。怎么辦?
other_func 參數(shù)肯定是需要的,只是直接放在 faker 不行而已。那么就多搞一個函數(shù)吧:
勝利的曙光已經(jīng)出現(xiàn)了。
上面 vs code 已經(jīng)提示出兩個錯誤。一個個來。
第一個問題,行16,我們希望 real_faker 調用后,返回 faker 函數(shù)本身。
簡單:
可以看到 行16 沒有提示錯誤了。
第二個問題,行12,找不著變量 other_func 。
簡單,在函數(shù) real_faker 中,不就有一個大大的參數(shù) other_func 。把整個 faker 函數(shù)移進去就可以:
現(xiàn)在 real_faker 就是帶有裝飾器效果。不過,可以看到,每次我們要裝飾一個函數(shù),都必須寫上 行17 的代碼。
所以,python 提供了一個簡化的語法。