裝飾器就是爲了在不改變函數代碼的狀況下爲函數添加新的功能app
實例函數
def note(func): "note function" print('note') def wrapper(x1,x2): "wrapper function" print(x1) print(x2) print('note something') # func(x1,x2) return func(x1,x2) return wrapper @note #test=note(test) def test(a1,a2): "test function" print('I am test') test(3,5) #note(test)() # print(test.__doc__)
帶參數的裝飾器,在普通裝飾器外邊再套一個函數,實現能夠傳遞額外參數
import time def time_logger(flag=0): def show_time(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) end_time=time.time() print(end_time-start_time) if flag: print('將這個操做記錄到日誌中') return wrapper return show_time @time_logger(1) def add(*args,**kwargs): time.sleep(1) sum=0 for i in args: sum+=i print(sum) add(1,5,9)
多層裝飾器
裝飾器函數的執行順序分爲(被裝飾函數)定義階段和(被裝飾函數)執行階段
在被裝飾函數定義階段,執行順序是從最靠近函數的裝飾器開始,自內而外執行
在被裝飾函數執行階段,執行順序由外而內
須要注意的是,裝飾器函數在被裝飾器函數定義好的時候就當即執行了
def A(fn): print('執行A') def inner1(): print('開始執行inner1') fn() print('結束inner1') return inner1 def B(fn): print('執行B') def inner2(): print('開始執行inner2') fn() print('結束inner2') return inner2 @A @B def hello(): #A(B(hello)) print('hello') hello()
執行B
執行A
開始執行inner1
開始執行inner2
hello
結束inner2
結束inner1spa
類裝飾器
須要依靠類內部的__call__方法
import time class Foo: def __init__(self,func): self.func=func def __call__(self, *args, **kwargs): start_time=time.time() self.func() end_time=time.time() print(end_time-start_time) @Foo #bar=Foo(bar) def bar(): print('bar') time.sleep(1) bar() #Foo(bar)()
functools.wraps,用於解決裝飾器的反作用
import functools def foo(): print('hello foo') print(foo.__name__) def C(func): # @functools.wraps(func) 能把原函數的原信息拷貝到裝飾器函數中,解決裝飾器的反作用 def inner(*args,**kwargs): print(func.__name__+'!!!!!') return func(*args,**kwargs) return inner @C def cal(x): return x+x*x print(cal(2)) print(cal.__name__) # foo # cal!!!!! # 6 # inner 這時的cal.__name__變成裝飾器內部函數的名稱了