Python裝飾器的調用過程


Python裝飾器的調用過程

  在Python學習的過程中,裝飾器是比較難理解的一個應用。本人也在學習期間也遇到很多坑,現將裝飾器的基本調用過程總結一下。

  首先,裝飾器用到了“閉包”,而“閉包”是學習裝飾器的基礎,所以在講裝飾器之前先將“閉包”的基本概念帶大家一起回顧一下:

  現有如下函數:

def func():
    def func1():
        print('i\'m func1')
    return func1
if __name__ == '__main__':   f
= func()
  f()
  print('函數func1的內存地址為:',f)

  我們在函數func()內部定義了另外一個函數func1(),最終return的是func1的內存地址。 

  函數定義完后,在全局把func()賦值給變量f,此時f中拿到的是func1的內存地址,這時候你可以把f看成是func1,進行f()操作相當於調用func1(),所以上面代碼的輸出結果為:

 

  此時有些人可能會問:既然f相當於func1,那么為何不在全局中直接調用func1()呢?答案是不行~因為func1()是在全局的函數func()里面定義的,全局情況下只能調用func(),不可以直接調用func()里面的函數:

  這里我們可以看到:"func1 is not defined",因為在全局程序只能調用func(),是找不到func1()的,跟別提調用了。

  所以,我們要想在全局情況下調用“全局函數”內部定義的函數,就必須令該全局函數返回“內部函數”的內存地址,然后將該內存地址賦值給一個變量,通過調用這個變量來實現“全局調用內部函數”,而此時,這個“內部的函數”就稱為“閉包”

  而上述例子中,函數func1就是一個閉包。

  理解了“閉包”的概念后我們再來看“裝飾器”的調用過程:

不帶參數的裝飾器

  如上圖:這里我們先定義了一個裝飾器Dec(),而Dec函數里面的outer函數就是一個閉包。當我們在函數func2定義前加上@Dec時,這個語句相當於:func2 = Dec(func2)。也就是說,我們在進行不帶參數的裝飾器的調用時,相當於把下面的函數名當做參數傳給了@后面的函數,@Dec也就相當於執行了Dec(func2)。后面就好理解了:Dec()函數返回了outer函數的內存地址,下面的func2()其實就調用了“閉包”outer(),進行了outer()函數里面的操作。

帶參數的裝飾器

  這里需要注意的是:如果要返回函數的話,帶參數的裝飾器就要寫三層內嵌函數。

  帶參數的裝飾器的具體執行過程分為兩步:首先執行Dec('QQ'),不管中間過程,Dec函數返回的是函數outer的內存地址,此時就變成了@outer,按照“不帶參數的裝飾器”的調用過程我們知道,此時outer將函數func2的名稱當做是參數執行outer里面的函數inner()。另外我們還需要注意:現在inner里不僅有func2,還有Dec本身所攜帶的參數'QQ'。

  此外:打印出來的"i'm inner"是在判定if type == 'QQ'后直接執行的;而"i'm func2"是inner()函數執行“outer函數所帶的參數”調用的結果,也就是說inner函數最后調用了“outer函數所帶的參數”func並執行了它,換句話講,inner就是一個閉包。


免責聲明!

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



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