Python里的裝飾器


裝飾器

裝飾器是干什么用的?
裝飾器可以在不修改某個函數的情況下,給函數添加功能。
形象點來說,從前有一個王叔叔,他一個人住在家里,每天打掃家,看書。於是定義如下一個函數:

def uncle_wang():
    sweeping()
    reading()

后來呢,有一天,大頭兒子一家搬到了王叔叔隔壁 😄 。根據劇情,一天,大頭兒子的媽媽請王叔叔來家里吃飯,那么,王叔叔的日程就添加了“去隔壁吃飯”這一項,但是又不能修改王叔叔之前的日程,怎么實現?這時,就可以給王叔叔添加一個裝飾器,給這個裝飾器起個名字,姑且就叫neighbor,然后就寫成這樣:

@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(),但是這個裝飾過的王叔叔已經不是原來的王叔叔了,他現在其實是隔壁老王。

王叔叔的新日程搞定了,但是還有個問題,就是順序。現在的日程順序相當於:

eat_next_door()
sweeping()
reading()

請人吃飯當然是吃晚飯啦,所以eat_next_door()需要排在最后面,而neighbor函數不能先返回(return func)然后才執行eat_next_door(),眾所周知,函數返回了就結束了,后面的東西都不管了。
所以,繼續套娃,再搞個函數進去,寫成這樣:

def neighbor(func):
    def wrapper():          # 套娃函數,注意這里是定義,不是執行
        func()              # 相當於不帶裝飾器的 uncle_wang()
        eat_next_door()     # 自定義函數,去隔壁吃飯
    return wrapper          # 直接返回套娃函數

這樣順序就對了,王叔叔很滿意~
現在這個裝飾器基本成型了,但是現在還不能處理原函數的參數和裝飾器函數的參數,繼續改進的實現方式可以去看廖雪峰老師的教程,寫得很不錯,我就是從那學來的。

附上完整代碼:

# !/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()

(嗨,又水了一篇,之前還說要測一下手動實現和庫函數實現的二分查找的耗時差距,正事還是放到下次吧……)

參考資料:

  1. 裝飾器 - 廖雪峰的官方網站
  2. 隔壁老王的梗是怎么來的 - 知乎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM