現在就來詳細講解一下python的裝飾器!
裝飾器的理解比較難,裝飾器的使用用到了閉包,閉包是學習裝飾器的基礎。所以先看閉包:
# coding:utf-8
def fun():
def fun1():
print("i am fun1")
return fun1 #這個地方返回fun1的記憶體位址
if __name__ == '__main__':
f = fun() #f儲存了fun1的記憶體位址
f() #執行f函式就是執行fun1函式
上面**中,我們首先執行f = fun()。這裡我們先走fun函式,fun()內部有fun1()函式,最終返回fun1的記憶體位址。
這時候你可能會問,f就是fun1,為什麼不能直接呼叫fun1呢,我們可以試試能不能呼叫:
因為fun1()是在全域性的函式fun()裡面定義的,全域性情況下只能呼叫fun(),不可以直接呼叫fun()裡面的函式。
我們要想在全域性情況下呼叫「全域性函式」內部定義的函式,就必須令該全域性函式返回「內部函式」的記憶體位址,然後將該記憶體位址賦值給乙個變數,通過呼叫這個變數來實現「全域性呼叫內部函式」,而此時,這個「內部的函式」就稱為「閉包」。
第一種:不帶引數的裝飾器:
這裡我們先定義了乙個裝飾器fun(),而fun函式裡面的fun1函式就是乙個閉包。當我們在函式main_fun定義前加上@fun時,這個語句相當於:main_fun = fun(main_fun)。也就是說,我們在進行不帶引數的裝飾器的呼叫時,相當於把下面的函式名當做引數傳給了@後面的函式,@fun也就相當於執行了fun(main_fun)。後面就好理解了:fun()函式返回了fun1函式的記憶體位址,下面的main_fun()其實就呼叫了「閉包」fun1(),進行了fun1()函式裡面的操作。
# coding:utf-8
def fun(func):
def fun1(*args):
print("我是閉包函式哦~",args)
func() #這個函式是傳進來的函式,與外界無關
return fun1 # 這個地方返回fun1的記憶體位址
@fun # 等價於 main_fun = fun(main_fun)
def main_fun():
print("我是被裝飾的函式哦~")
if __name__ == '__main__':
main_fun() #執行這個函式就直接跳到閉包裡面去了。這個函式是否執行,取決於閉包裡面是否呼叫
main_fun("我是引數") #傳遞的引數會被帶到閉包裡面去接接收引數。
第二種:帶引數的裝飾器
執行結果:
這裡需要注意的是:如果要返回函式的話,帶引數的裝飾器就要寫三層內嵌函式。
帶引數的裝飾器的具體執行過程分為兩步:首先執行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就是乙個閉包。
python裝飾器 python 裝飾器詳解
def outer x def inner y return x y return inner print outer 6 5 11 如 所示,在outer函式內,又定義了乙個inner函式,並且inner函式又引用了外部函式outer的變數x,這就是乙個閉包了。在輸出時,outer 6 5 第乙個...
python裝飾器詳解 python裝飾器詳解
按照 python 的程式設計原則,當乙個函式被定義後,如要修改或擴充套件其功能應盡量避免直接修改函式定義的 段,否則該函式在其他地方被呼叫時將無法正常執行。因此,當需要修改或擴充套件已被定義的函式的功能而不希望直接修改其 時,可以使用裝飾器。先來看乙個簡單的例子 def func1 functio...
詳解Python裝飾器
裝飾器的難點 在梳理了裝飾器的整個內容之後,我認為難點不是裝飾器本身,而是直接呼叫被裝飾的函式,讓人無法理解背後究竟發生了什麼。一 引出裝飾器概念 引入問題 定義了乙個函式,想在執行時動態的增加功能,又不想改動函式本身的 示例 希望對下列函式呼叫增加log功能,列印出函式呼叫 def f1 x re...