定義:app
器字表明函數,裝飾器本質是函數;裝飾:裝飾其餘函數,就是爲其餘函數添加附加功能函數
原則:spa
1.不能修改被裝飾函數的源代碼(在不修改被裝飾函數源代碼的狀況下爲其添加功能)3d
2.不能修改被裝飾的函數的調用函數,被裝飾函數不知道被裝飾了code
實現裝飾器須要瞭解:blog
1.函數及變量:內存存儲函數方式與存儲變量同樣:內存中存儲函數體,再指向函數名ip
2.高階函數內存
a.把一個函數名看成實參傳給另外個函數(在不修改被裝飾函數源代碼的狀況下爲其添加功能)input
b.返回值中包含函數名(不修改函數的調用方式)it
1 import time 2 def bar():#bar是這個函數的門牌號 3 time.sleep(2) 4 print('in the bar') 5 def test1(func):#不是裝飾器,是由於函數的調用方式test1(bar)被更改了 6 start_time=time.time() 7 func() 8 stop_time=time.time() 9 print('the func fun time is %s' % (stop_time-start_time)) 10 11 test1(bar) #func=bar
運行結果:
1 import time 2 def bar():#bar是這個函數的門牌號 3 time.sleep(2) 4 print('in the bar') 5 6 def test2(func): 7 print(func) 8 return func 9 10 print(test2(bar)) 11 print('--------------------') 12 bar=test2(bar) 13 print('--------------------') 14 bar()
運行結果:
3.嵌套函數:在已定義的函數內部再定義函數
1 def foo(): 2 print('in the foo') 3 def bar():#bar具備局部變量的特性 4 print('in the bar')
經過高階函數和嵌套函數實現裝飾器功能:
1 import time 2 3 def timer(func):#在被裝飾函數以外嵌套裝飾器函數,添加裝飾功能 4 def deco(*args,**kwargs):#不固定參數參數 5 start_time=time.time() 6 result=func(*args,**kwargs)#被裝飾的函數在這運行 7 stop_time=time.time() 8 print('the func run time is %s' % (stop_time-start_time)) 9 10 return result#加入了返回值 11 return deco#timer這個函數返回了deco函數的地址 12 13 @timer#@timer等於test1=timer(test1):返回了deco函數的內存地址賦給了test1,此時test1是新的test1,這時的test1已經有了裝飾器的功能 14 def test1(): 15 time.sleep(3) 16 print('in the test1') 17 18 @timer#test2=timer(test2),deco=test2 19 def test2(name): 20 time.sleep(3) 21 print('test2:',name) 22 print('in the test2') 23 return 'from test2'#加入了返回,裝飾器內的函數也要加返回 24 25 test1() 26 print('-----------------') 27 print(test2('tao'))#print打印函數的返回值
運行結果:
因此說,裝飾器就是將被裝飾函數在裝飾器函數內執行,再將裝飾器函數賦予被裝飾函數名,以後再執行被裝飾函數時就至關於執行了裝飾器函數,即在沒有改變被裝飾函數的源代碼和調用方式的狀況下,實現了裝飾的功能。
實現加入參數的裝飾器:
1 user,passwd='Tao','abc' 2 def auth(auth_type):#與未加參數的裝飾器區別:裝飾器多加了一個參數,要多嵌套一層函數;auth返回的還是wrapper這個函數 3 def outer_wrapper(func):#注意加入的參數和func的位置 4 def wrapper(*args, **kwargs):#auth函數返回out_wrapper,out_wrapper函數返回wrapper,因此auth函數返回的還是wrapper這個函數 5 6 #判斷參數 7 if auth_type=='local': 8 username = input('username:').strip() 9 password = input('passwd:').strip() 10 11 if user == username and passwd == password: 12 print('歡迎') 13 res = func(*args, **kwargs) #當被裝飾函數有返回值時 14 return res 15 else: 16 exit('錯誤') 17 18 #判斷參數 19 elif auth_type=='ldap': 20 print('ldap沒法實現') 21 22 return wrapper 23 24 return outer_wrapper 25 26 27 28 def index(): 29 print('welcome to index page') 30 31 @auth(auth_type='local')#auth返回了wrapper這個函數賦給了home 32 def home(): 33 print('welcome to home page') 34 return "from home" #加入了返回,裝飾器內的函數也要加返回 35 36 @auth(auth_type='ldap')#auth返回了wrapper這個函數賦給了bbs 37 def bbs(): 38 print('welcome to bbs page') 39 40 index() 41 print('--------------------') 42 print(home())#打印函數的返回值即from home 43 print('--------------------') 44 bbs()
運行結果: