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 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()的返回值
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__) #打印函數名
無參裝飾器(雙層閉包函數):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