1、簡單的裝飾器python
裝飾器本質上就是一個python函數,可讓其餘函數在不須要任何代碼變更的前提下,增長額外的功能,裝飾器的返回值也是一個函數對象。緩存
簡單來說,在原有的函數先後增長功能,且不改變原函數的調用方式。閉包
裝飾器的本質:就是一個閉包函數app
裝飾器的應用場景:插入日誌、性能測試、事務處理、緩存等等場景。ide
實現計算每一個函數的執行時間的功能:函數
1 import time 2 def timmer(f): 3 def inner(): 4 start_time = time.time() 5 f() 6 end_time = time.time() 7 print(end_time - start_time) 8 return inner 9 10 def func(): 11 print('begin func') 12 time.sleep(0.1) 13 print('end func') 14 15 func = timmer(func) 16 func() # ==> inner()
以上功能不簡潔,不完美。引出語法糖。性能
1 import time 2 def timmer(f): 3 def inner(): 4 start_time = time.time() 5 f() 6 end_time = time.time() 7 print(end_time - start_time) 8 return inner 9 10 @timmer # ==> func = timmer(func) 11 def func(): 12 print('begin func') 13 time.sleep(0.1) 14 print('end func') 15 16 func() # ==> inner()
以上裝飾器都是不帶參數函數,如今裝飾一個帶參數的該怎麼辦?測試
1 import time 2 def timmer(f): 3 def inner(*args,**kwargs): 4 start_time = time.time() 5 ret = f(*args,**kwargs) 6 end_time = time.time() 7 print(end_time - start_time) 8 return ret 9 return inner 10 11 @timmer # ==> func = timmer(func) 12 def func(a,b): 13 print('begin func',a) 14 time.sleep(0.1) 15 print('end func',b) 16 return True 17 18 func(1,2) # ==> inner()
1 import time 2
3 def timer(func): 4 def inner(a): 5 start = time.time() 6 func(a) 7 print(time.time() - start) 8 return inner 9
10 @timer 11 def func1(a): 12 print(a) 13
14 func1(1)
1 import time 2 def timer(func): 3 def inner(*args,**kwargs): 4 start = time.time() 5 re = func(*args,**kwargs) 6 end=time.time() 7 print(end- start) 8 return re 9 return inner 10
11 @timer #==> func1 = timer(func1)
12 def func1(a,b): 13 print('in func1') 14 print(a,b) 15
16 @timer #==> func1 = timer(func1)
17 def func2(a): 18 print('in func2 and get a:%s'%(a)) 19 return 'fun2 over'
20
21 func1(1,2) 22 print(func2('aaaaaa'))
1 import time 2 def timer(func): 3 def inner(*args,**kwargs): 4 start = time.time() 5 re = func(*args,**kwargs) 6 end=time.time() 7 print(end - start) 8 return re 9 return inner 10
11 @timer #==> func1 = timer(func1)
12 def jjj(a): 13 print('in jjj and get a:%s'%(a)) 14 return 'fun2 over'
15
16 jjj('aaaaaa') 17 print(jjj('aaaaaa'))
2、開放封閉原則spa
1.對擴展是開放的
任何一個程序,不可能在設計之初就已經想好了全部的功能而且將來不作任何更新和修改。因此咱們必須容許代碼擴展、添加新功能。
2.對修改是封閉的
由於咱們寫的一個函數,頗有可能已經交付給其餘人使用了,若是這個時候咱們對其進行了修改,頗有可能影響其餘已經在使用該函數的用戶。
裝飾器完美的遵循了這個開放封閉原則。設計
3、裝飾器的固定結構
1 def timmer(f): 2 def inner(*args,**kwargs): 3 '''執行函數以前要作的''' 4 ret = f(*args,**kwargs) 5 '''執行函數以後要作的''' 6 return ret 7 return inner
4、帶參數的裝飾器
帶參數的裝飾器:就是給裝飾器傳參
用處:就是當加了不少裝飾器的時候,如今突然又不想加裝飾器了,想把裝飾器給去掉,可是那麼多代碼,一個一個去顯得麻煩,因此,能夠利用帶參數的裝飾器去裝飾它,就像一個開關,須要的時候就打開調用,不須要的時候就關閉去掉。給裝飾器裏面傳個參數,那麼這個語法糖也要帶個括號。在語法糖括號內傳參。能夠用三層嵌套,弄一個標識
1 # 帶參數的裝飾器:(至關於開關)爲了給裝飾器傳參
2 F=True#爲True時就把裝飾器給加上了
3 # F=False#爲False時就把裝飾器給去掉了
4 def outer(flag): 5 def wrapper(func): 6 def inner(*args,**kwargs): 7 if flag: 8 print('before') 9 ret=func(*args,**kwargs) 10 print('after') 11 else: 12 ret = func(*args, **kwargs) 13 return ret 14 return inner 15 return wrapper 16
17 @outer(F)#@wrapper
18 def hahaha(): 19 print('hahaha') 20
21 @outer(F) 22 def shuangwaiwai(): 23 print('shuangwaiwai') 24
25 hahaha() 26 shuangwaiwai()
5、多個裝飾器裝飾一個函數
1 def qqqxing(fun): 2 def inner(*args,**kwargs): 3 print('in qqxing: before') 4 ret = fun(*args,**kwargs) 5 print('in qqxing: after') 6 return ret 7 return inner 8
9 def pipixia(fun): 10 def inner(*args,**kwargs): 11 print('in qqxing: before') 12 ret = fun(*args,**kwargs) 13 print('in qqxing: after') 14 return ret 15 return inner 16 @qqqxing 17 @pipixia 18 def dapangxie(): 19 print('餓了嗎') 20 dapangxie() 21
22 '''
23 @qqqxing和@pipixia的執行順序:先執行qqqxing裏面的 print('in qqxing: before'),而後跳到了pipixia裏面的 24 print('in qqxing: before') 25 ret = fun(*args,**kwargs) 26 print('in qqxing: after'),完了又回到了qqqxing裏面的 print('in qqxing: after')。因此就以下面的運行結果截圖同樣 27 '''
6、進階需求
第一種狀況:
# 500個函數
# 設計你的裝飾器 從而確認是夠生效
1 import time 2 def outer(flag): 3 def timmer(f): 4 def inner(*args,**kwargs): 5 if flag == True: 6 start_time = time.time() 7 ret = f(*args,**kwargs) 8 end_time = time.time() 9 print(end_time - start_time) 10 else: 11 ret = f(*args,**kwargs) 12 return ret 13 return inner 14 return timmer 15 16 @outer(False) 17 def func(a,b): 18 print('begin func',a) 19 time.sleep(0.1) 20 print('end func',b) 21 return True 22 23 func(1,2)
第二種狀況:
# 裝飾器:登陸、記錄日誌
1 login_info = {'alex':False} 2 def login(func): 3 def inner(name): 4 if login_info[name] != True: 5 user = input('user:') 6 pwd = input('pwd:') 7 if user == 'alex' and pwd == 'alex3714': 8 login_info[name] = True 9 if login_info[name] == True: 10 ret = func(name) 11 return ret 12 return inner 13 14 @login 15 def index(name): 16 print('歡迎%s來到博客園首頁~' %name) 17 18 @login 19 def manager(name): 20 print('歡迎%s來到博客園管理頁~' %name) 21 22 index('alex') 23 index('alex') 24 manager('alex') 25 manager('alex')
1 import time 2 login_info = {'alex':False} 3 def login(func): # manager 4 def inner(name): 5 if login_info[name] != True: 6 user = input('user :') 7 pwd = input('pwd :') 8 if user == 'alex' and pwd == 'alex3714': 9 login_info[name] = True 10 if login_info[name] == True: 11 ret = func(name) # timmer中的inner 12 return ret 13 return inner 14 15 def timmer(f): 16 def inner(*args,**kwargs): 17 start_time = time.time() 18 ret = f(*args,**kwargs) # 調用被裝飾的方法 19 end_time = time.time() # 20 print(end_time - start_time) 21 return ret 22 return inner 23 24 @login 25 @timmer 26 def index(name): 27 print('歡迎%s來到博客園首頁~'%name) 28 29 @login 30 @timmer # manager = login(manager) 31 def manager(name): 32 print('歡迎%s來到博客園管理頁~'%name) 33 34 index('alex') 35 index('alex') 36 manager('alex') 37 manager('alex')
1 l=[] 2 def wrapper(fun): 3 l.append(fun)#統計當前程序中有多少個函數被裝飾了
4 def inner(*args,**kwargs): 5 # l.append(fun)#統計本次程序執行有多少個帶裝飾器的函數被調用了
6 ret = fun(*args,**kwargs) 7 return ret 8 return inner 9
10 @wrapper 11 def f1(): 12 print('in f1') 13
14 @wrapper 15 def f2(): 16 print('in f2') 17
18 @wrapper 19 def f3(): 20 print('in f3') 21 print(l)
7、總結
# 裝飾器的進階
# 給裝飾器加上一個開關 - 從外部傳了一個參數到裝飾器內
# 多個裝飾器裝飾同一個函數 - 套娃
# 每一個裝飾器都完成一個獨立的功能
# 功能與功能之間互相分離
# 同一個函數須要兩個或以上額外的功能
1 def wrapper1(func): 2 def inner(*args,**kwargs): 3 '''執行a代碼''' 4 ret = func(*args,**kwargs) 5 '''執行b代碼''' 6 return ret 7 return inner 8 9 def wrapper2(func): 10 def inner(*args,**kwargs): 11 '''執行c代碼''' 12 ret = func(*args,**kwargs) 13 '''執行d代碼''' 14 return ret 15 return inner 16 17 @wrapper1 18 @wrapper2 19 def func():pass