裝飾器本質上就是一個python函數,他可讓其餘函數在不須要作任何代碼變更的前提下,增長額外的功能,裝飾器的返回值也是一個函數對象。python
裝飾器的應用場景:好比插入日誌,性能測試,事務處理,緩存等等場景。緩存
如今我有一個需求,我想讓你測試這個函數的執行時間,在不改變這個函數代碼的狀況下:app
import time函數
def func1():
print('in func1')性能
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner測試
func1 = timer(func1)
func1()spa
裝飾器---簡單版設計
可是若是有多個函數,我都想讓你測試他們的執行時間,你每次是否是都得func1 = timer(func1)?這樣仍是有點麻煩,由於這些函數的函數名多是不相同,有func1,func2,graph,等等,因此更簡單的方法,python給你提供了,那就是語法糖。日誌
import time
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return innercode
@timer #==> func1 = timer(func1)
def func1():
print('in func1')
func1()
裝飾器---語法糖
剛剛咱們討論的裝飾器都是裝飾不帶參數的函數,如今要裝飾一個帶參數的函數怎麼辦呢?
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner
@timer
def func1(a):
print(a)
func1(1)
裝飾器——帶參數的裝飾器
裝飾器---帶參數的裝飾器
import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func1 = timer(func1)
def func1(a,b):
print('in func1')
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
裝飾器---hold住全部參數的裝飾器
上面的裝飾器已經很是完美了,可是有咱們正常狀況下查看函數信息的方法在此處都會失效:
def index(): '''這是一個主頁信息''' print('from index') print(index.__doc__) #查看函數註釋的方法 print(index.__name__) #查看函數名的方法
如何解決呢?
from functools import wraps def deco(func): @wraps(func) #加在最內層函數正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper @deco def index(): '''哈哈哈哈''' print('from index') print(index.__doc__) print(index.__name__)
1.對擴展是開放的
爲何要對擴展開放呢?
咱們說,任何一個程序,不可能在設計之初就已經想好了全部的功能而且將來不作任何更新和修改。因此咱們必須容許代碼擴展、添加新功能。
2.對修改是封閉的
爲何要對修改封閉呢?
就像咱們剛剛提到的,由於咱們寫的一個函數,頗有可能已經交付給其餘人使用了,若是這個時候咱們對其進行了修改,頗有可能影響其餘已經在使用該函數的用戶。
裝飾器完美的遵循了這個開放封閉原則。
def timer(func):
def inner(*args,**kwargs):
'''執行函數以前要作的'''
re = func(*args,**kwargs)
'''執行函數以後要作的'''
return re
return inner
裝飾器的固定格式
from functools import wraps
def deco(func):
@wraps(func) #加在最內層函數正上方
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper
裝飾器的固定格式--wraps版
假如你有成千上萬個函數使用了一個裝飾器,如今你想把這些裝飾器都取消掉,你要怎麼作?
一個一個的取消掉? 沒日沒夜忙活3天。。。
過兩天你領導想通了,再讓你加上。。。
def outer(flag):
def timer(func):
def inner(*args,**kwargs):
if flag:
print('''執行函數以前要作的''')
re = func(*args,**kwargs)
if flag:
print('''執行函數以後要作的''')
return re
return inner
return timer
@outer(False)
def func():
print(111)
func()
帶參數的裝飾器
def wrapper1(func):
def inner():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner
def wrapper2(func):
def inner():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner
@wrapper2
@wrapper1
def f():
print('in f')
f()
多個裝飾器裝飾一個函數