day3-python之裝飾器(四)

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
裝飾器的固定格式
裝飾器的固定格式--wraps版

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
相關文章
相關標籤/搜索