裝飾器

 裝飾器概念

1 什麼是裝飾器
器=>工具
裝飾=>指的是爲被裝飾對象添加新功能

裝飾器自己能夠是任意可調用的對象=>函數
被裝飾的對象也能夠是任意可調用的對象=>函數

目標:寫一個函數來爲另一個函數添加新功能
2 爲什麼要用裝飾器
開放封閉原則: 軟件一旦上線就應該對修改封閉,對擴展開放
對修改封閉:
1. 不能修改功能的源代碼
2. 也不能修改功能的調用方式

對擴展開發:
能夠爲原有的功能添加新的功能
裝飾器就是要在不修改功能源代碼以及調用方式的前提下爲原功能添加額外新的功能
3 如何用裝飾器

 

裝飾器代碼

#統計不一樣程序的運行時間
import time
def index():
    print('welcome to index page')
    time.sleep(3)
#統計誰的時間,傳誰
def outter(func):
    # func=最原始那個index的內存地址
    def wrapper():
        start = time.time()
        func()  # 最原始那個index的內存地址()
        stop = time.time()
        print('run time is %s' % (stop - start))
    return wrapper
#下面一行的目的是偷樑換柱
index = outter(index)  # index=outter(最原始那個index的內地址) #index=wrapper函數的內地址
                       #爲了避免改變調用方式,將變量名定義爲index
index()                #調用wraper(),index的地址已經變成wrapper的地址

 裝飾器修正1:

   #須要獲得被裝飾函數的返回值
1
import time 2 3 def index(): 4 print('welcome to index page') 5 time.sleep(3) 6 return 123 7 8 =================================== 9 def outter(func): 10 # func=最原始那個index的內存地址 11 def wrapper(): 12 start=time.time() 13 res=func() # 最原始那個index的內存地址() 14 stop=time.time() 15 print('run time is %s' %(stop-start)) 16 return res  #res是index()的返回值 17 return wrapper 18 19 index=outter(index) #index=outter(最原始那個index的內地址) #index=wrapper函數的內地址 20 =================================== 21 22 res=index() #res=wraper()實際調用 23 print(res) #打原始index()的返回值

裝飾器修正2:

 1 #當對多個方法進行裝飾時,須要傳入不一樣參數
 2 import time
 3 
 4 def index():
 5     print('welcome to index page')
 6     time.sleep(3)
 7     return 123
 8 
 9 def home(name):
10     print('welcome %s to home page' %name)
11     time.sleep(1)
12 
13 #==================================
14 def outter(func):
15     # func=最原始那個home的內地址
16     def wrapper(*args,**kwargs):#能夠傳入任意參數,此處只是做爲參數的中轉,而後給傳給func() 17         start=time.time()
18         res=func(*args,**kwargs)
19         stop=time.time()
20         print('run time is %s' %(stop-start))
21         return res
22     return wrapper
23 
24 index=outter(index) #index=outter(最原始那個index的內地址) #index=wrapper函數的內地址
25 home=outter(home) #index=outter(最原始那個home的內地址) #home=wrapper函數的內地址
26 #===================================
27 
28 home('egon') #wrapper('egon')
29 index() #wrapper()

 

 裝飾器的語法糖:

@裝飾器的名字:要在被裝飾對象正上方單獨一行寫上
@timmer----->至關於func=timmer(func)括號內func-->爲最原始的那個要被修飾的函數的內存地址)
 1 from functools import wraps#引用外部工具包來自動顯示被裝飾函數的方法名以及函數註釋
 2 
 3 import time
 4 def timmer(func): # func=最原始那個home的內地址
 5     @wraps(func)
 6     def wrapper(*args,**kwargs):
 7         start=time.time()
 8         res=func(*args,**kwargs)
 9         stop=time.time()
10         print('run time is %s' %(stop-start))
11         return res
12     return wrapper
13 
14 @timmer  #index=timmer(index) #index=timmer(最原始那個index內存地址) #index=wrapper函數的內存地址
15 def index():
16     """這是index功能"""
17     print('welcome to index page')
18     time.sleep(3)
19     return 123
20 
21 @timmer #home=timmer(home) #home=timmer(最原始那個home內存地址) #home=wrapper函數的內存地址
22 def home(name): 
23   """這是home功能"""
24   print('welcome %s to home page' %name)
25   time.sleep(1)
26
27 print(help(index))  #打印函數註釋
28 print(index.__name__) #打印函數名

 無參裝飾器與有參裝飾器(核心都是偷樑換柱爲wrapper函數):

無參裝飾器(雙層閉包函數):mysql

#無參裝飾器的模板
def outter(func):
    def wrapper(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return wrapper

無參裝飾器:sql

 1 #登陸狀態驗證,帳戶驗證
 2 import time
 3 
 4 user_info={'current_user':None}#定義初始用戶狀態
 5 
 6 def auth(func):
 7     def wrapper(*args,**kwargs):
 8         if user_info['current_user'] is not None:#說明已經登陸了
 9             res=func(*args,**kwargs)
10             return res
11         inp_user=input('username>>>: ').strip()
12         inp_pwd=input('password>>>: ').strip()
13         if inp_user == 'egon' and inp_pwd == '123':
14             # 記錄登陸狀態
15             user_info['current_user']=inp_user
16 
17             print('login successful')
18             res=func(*args,**kwargs)
19             return res
20         else:
21             print('user or password error')
22     return wrapper
23 
24 @auth
25 def index():
26     """這是index功能"""
27     print('welcome to index page')
28     time.sleep(2)
29     return 123
30 
31 @auth
32 def home(name):
33     """這是home功能"""
34     print('welcome %s to home page' %name)
35     time.sleep(1)
36 
37 index()
38 home('egon')

 

 有參裝飾器(三層閉包函數,第三層用來傳值閉包

#有參裝飾器模板
def outter2(xxx,yyy):
    def outter(func):    #被裝飾函數名,不能加參數
        def wrapper(*args,**kwargs):#只是做爲參數中轉,不可加參數
            res=func(*args,**kwargs)
            print(xxx)  #要引用外部參數,只能經過外部函數傳
            print(yyy)
            return res
        return wrapper
    return outter

 有參裝飾器:app

 1 #判斷數據來源,根據不一樣來源作不一樣操做
 2 import time
 3 
 4 user_info={'current_user':None}
 5 
 6 def auth2(engine='file'):
 7     def auth(func):
 8         def wrapper(*args,**kwargs):
 9             if user_info['current_user'] is not None:
10                 res=func(*args,**kwargs)
11                 return res
12             inp_user=input('username>>>: ').strip()
13             inp_pwd=input('password>>>: ').strip()
14 
15             if engine == 'file':
16                 print('基於文件的認證')
17                 if inp_user == 'egon' and inp_pwd == '123':
18                     # 記錄登陸狀態
19                     user_info['current_user']=inp_user
20 
21                     print('login successful')
22                     res=func(*args,**kwargs)
23                     return res
24                 else:
25                     print('user or password error')
26             elif engine == 'mysql':
27                 print('基於mysql數據的認證')
28             elif engine == 'ldap':
29                 print('基於ldap的認證')
30             else:
31                 print('沒法識別認證源')
32         return wrapper
33     return auth
34 
35 @auth2(engine='mysql') # @auth ===> index=auth(最原始那個index的內存地址)===》index=wrapper
36 def index():
37     """這是index功能"""
38     print('welcome to index page')
39     time.sleep(2)
40     return 123
41 
42 @auth2(engine='file')
43 def home(name):
44     """這是home功能"""
45     print('welcome %s to home page' %name)
46     time.sleep(1)
47 
48 index()     #wrapper()
49 home('egon')#wrapper('egon')

 裝飾器疊加:

加載裝飾器就是將原函數名偷樑換柱成了裝飾器最內層那個wrapper函數
在加載完畢後,調用原函數其實就是在調用wrapper函數

當一個被裝飾的對象同時疊加多個裝飾器時
  裝飾器的加載順序是:自下而上
  裝飾器內wrapper函數的執行順序是:自上而下

 1 import time
 2 
 3 def timmer(func): #func=wrapper2的內存地址
 4     def wrapper1(*args, **kwargs):
 5         print('==================>wrapper1運行了')
 6         start=time.time()
 7         res = func(*args, **kwargs) #===================>跳到wrapper2去執行了,
 8         stop=time.time()
 9         print('run time is %s' %(stop - start))
10         return res
11     return wrapper1
12 
13 def auth(engine='file'):
14     def xxx(func): # func=最原始那個index的內存地址
15         def wrapper2(*args, **kwargs):
16             print('================>wrapper2運行了')
17             name=input('username>>>: ').strip()
18             pwd=input('password>>>: ').strip()
19             if engine == 'file':
20                 print('基於文件的認證')
21                 if name == 'egon' and pwd  == '123':
22                     print('login successfull')
23                     res = func(*args, **kwargs)
24                     return res
25             elif engine == 'mysql':
26                 print('基於mysql的認證')
27             elif engine == 'ldap':
28                 print('基於ldap的認證')
29             else:
30                 print('錯誤的認證源')
31         return wrapper2
32     return xxx
33 
34 @timmer # index=timmer(wrapper2的內存地址) #index=wrapper1的內存地址
35 @auth(engine='file') #@xxx #index=xxx(最原始那個index的內存地址) #index=wrapper2的內存地址
36 def index():
37     print('welcome to index page')
38     time.sleep(2)
39 
40 index() #wrapper1的內存地址()
# ==================================>wrapper1運行了
# ===================================>wrapper2運行了
# username>>>: egon
# password>>>: 123
# 基於文件的認證
# login successfull
# welcome to index page
# run time is 11.126000165939331
 

 

 1 import time
 2 
 3 def timmer(func): #func=wrapper2的內存地址
 4     def wrapper1(*args, **kwargs):
 5         print('=================>wrapper1運行了')
 6         start=time.time()
 7         res = func(*args, **kwargs) #=================>跳到wrapper2去執行了,
 8         stop=time.time()
 9         print('run time is %s' %(stop - start))
10         return res
11     return wrapper1
12 
13 def auth(engine='file'):
14     def xxx(func): # func=最原始那個index的內存地址
15         def wrapper2(*args, **kwargs):
16             print('===============>wrapper2運行了')
17             name=input('username>>>: ').strip()
18             pwd=input('password>>>: ').strip()
19             if engine == 'file':
20                 print('基於文件的認證')
21                 if name == 'egon' and pwd  == '123':
22                     print('login successfull')
23                     res = func(*args, **kwargs)
24                     return res
25             elif engine == 'mysql':
26                 print('基於mysql的認證')
27             elif engine == 'ldap':
28                 print('基於ldap的認證')
29             else:
30                 print('錯誤的認證源')
31         return wrapper2
32     return xxx
33 
34 @auth(engine='file')
35 @timmer
36 def index():
37     print('welcome to index page')
38     time.sleep(2)
39 
40 index() #wrapper1的內存地址()
41
#===================================>wrapper2運行了# username>>>: egon# password>>>: 123# 基於文件的認證# login successfull# ===================================>wrapper1運行了# welcome to index page# run time is 2.0189998149871826
相關文章
相關標籤/搜索