裝飾器是幹什麼用的?
裝飾器能夠在不修改某個函數的狀況下,給函數添加功能。
形象點來講,從前有一個王叔叔,他一我的住在家裏,天天打掃家,看書。因而定義以下一個函數:python
def uncle_wang(): sweeping() reading()
後來呢,有一天,大頭兒子一家搬到了王叔叔隔壁 :-D 。根據劇情,一天,大頭兒子的媽媽請王叔叔來家裏吃飯,那麼,王叔叔的日程就添加了「去隔壁吃飯」這一項,可是又不能修改王叔叔以前的日程,怎麼實現?這時,就能夠給王叔叔添加一個裝飾器,給這個裝飾器起個名字,姑且就叫neighbor
,而後就寫成這樣:app
@neighbor def uncle_wang(): sweeping() reading()
而後王叔叔去大頭兒子家吃飯就提上日程啦,哈哈。(只是吃飯哦,不要想多了(⊙v⊙))
這個neighbor
其實也是個函數,參數就是uncle_wang
(沒錯,能夠把函數名當成參數傳來傳去,還能當作返回值),在裝飾器裏面實現「去隔壁吃飯」:函數
def neighbor(func): eat_next_door() # 自定義函數,去隔壁吃飯 return func # 原來的函數不變,直接返回
最後是執行,直接運行uncle_wang()
便可網站
# 執行函數 uncle_wang() # 至關於不加裝飾器,直接執行 neighbor(uncle_wang)()
這感受就像是用neighbor
裝飾了uncle_wang
,豐富了王叔叔的生活,今後變成了隔壁老王。實現方式就是套娃,給uncle_wang
套個neighbor
,變成neighbor(uncle_wang)
(這整個東西是個函數名),而後調用這個函數: neighbor(uncle_wang)()
,形如:函數名()
在Python裏,這個套娃的操做簡化成了裝飾器,直接在原函數上面添加@neighbor
,而後調用的時候仍是寫成uncle_wang()
,可是這個裝飾過的王叔叔已經不是原來的王叔叔了,他如今實際上是隔壁老王。code
王叔叔的新日程搞定了,可是還有個問題,就是順序。如今的日程順序至關於:教程
eat_next_door() sweeping() reading()
請人吃飯固然是吃晚飯啦,因此eat_next_door()
須要排在最後面,而neighbor
函數不能先返回(return func
)而後才執行eat_next_door()
,衆所周知,函數返回了就結束了,後面的東西都無論了。
因此,繼續套娃,再搞個函數進去,寫成這樣:utf-8
def neighbor(func): def wrapper(): # 套娃函數,注意這裏是定義,不是執行 func() # 至關於不帶裝飾器的 uncle_wang() eat_next_door() # 自定義函數,去隔壁吃飯 return wrapper # 直接返回套娃函數
這樣順序就對了,王叔叔很滿意~
如今這個裝飾器基本成型了,可是如今還不能處理原函數的參數和裝飾器函數的參數,繼續改進的實現方式能夠去看廖雪峯老師的教程,寫得很不錯,我就是從那學來的。get
附上完整代碼:io
# !/usr/bin/env python3 # -*- coding: utf-8 -*- def sweeping(): print('sweeping') def reading(): print('reading') def eat_next_door(): print('eat_next_door') def neighbor(func): def wrapper(): # 套娃函數,注意這裏是定義,不是執行 func() # 至關於不帶裝飾器的 uncle_wang() eat_next_door() # 自定義函數,去隔壁吃飯 return wrapper # 直接返回套娃函數 @neighbor def uncle_wang(): sweeping() reading() if __name__ == "__main__": uncle_wang()
(嗨,又水了一篇,以前還說要測一下手動實現和庫函數實現的二分查找的耗時差距,正事仍是放到下次吧……)class
參考資料: