裝飾器這玩意挺有用,當時感受各類繞,如今終於繞明白了,俺滴個大爺,仍是要慢慢思考才能買明白各類的真諦,沒事就來繞一繞函數
def outer(func):
def inner():
print("認證成功")
result=func()
print("登陸成功")
return result
return inner
@outer
def OA():
print("OA接口")
這裏面須要注意的是:
- @outer和@outer()有區別,沒有括號時,outer函數依然會被執行,這和傳統的用括號才能調用函數不一樣,須要特別注意!
- 是OA這個函數名(而不是OA()這樣被調用後)當作參數傳遞給裝飾函數outer,也就是:func = OA,@outer等於outer(OA),實際上傳遞了OA的函數體,而不是執行OA後的返回值。
- outer函數return的是inner這個函數名,而不是inner()這樣被調用後的返回值。
1. 程序開始執行outer函數內部的內容,一開始它又碰到了一個函數,inner函數定義塊被程序觀察到後不會馬上執行,而是讀入內存中。
2. 再往下,碰到return inner,返回值是個函數名,而且這個函數名會被賦值給OA這個被裝飾的函數,也就是OA = inner,此時OA函數被新的函數inner覆蓋了(其實是OA這個函數名更改爲指向inner這個函數名指向的函數體內存地址,OA再也不指向它原來的函數體的內存地址),再日後調用OA的時候將執行inner函數內的代碼,而不是先前的函數體。那麼先前的函數體去哪了?還記得咱們將OA當作參數傳遞給func這個形參麼?func這個變量保存了老的函數在內存中的地址,經過它就能夠執行 老的函數體,你能在inner函數裏看到result = func()這句代碼,它就是這麼作的!
3.接下來,尚未結束,依然經過OA()的方式調用OA 函數時,執行的就再也不是老的OA函數的代碼,而是inner函數的代碼。在本例中,它首先會打印個「認證成功」的提示,而後,它會執行func函數並將返回值賦值個變量result,這個func函數就是老的OA函數;接着,它又打印了「登錄成功」的提示;最後返回result這個變量。咱們能夠用 r = OA()的方式接受result的值。
4.僅僅是添加了一個裝飾函數,就實現了咱們的需求,在函數調用前先認證,調用後寫入日誌,這就是裝飾器的最大做用。