對於裝飾器來講,就是在不改變函數的調用的狀況下,對函數的先後增長了些許功能,這徹底符合函數的 開放封閉 原則。裝飾器的本質 其實就是一個閉包函數。閉包
這是一個裝飾器的步驟圖app
def wrapper(func): # 2 def inner(*args,**kwargs): # 5 ret = func(*args,**kwargs) # 6 return ret #10 return inner # 3 @wrapper #shopping = wrappers(shooping) # 1 --shopping = innner def shopping(num): #7 print(num) # 8 return 1 # 9 print(shopping(5)) # 4
這樣你調 shopping 時, 真實狀況是你在調用 inner 函數。若是 你想打印其函數名時打印的實際上是 innner 函數。函數
from functools import wraps def wrapper(func): # 2 @wraps(func) def inner(*args,**kwargs): # 5 ret = func(*args,**kwargs) # 6 return ret #10 return inner # 3 @wrapper #shopping = wrappers(shooping) # 1 --shopping = innner def shopping(num): #7 print(num) # 8 return 1 # 9 print(shopping(5)) # 4 print(shopping.__name__) #以字符串的形式獲取到函數名
print(shopping.__doc__) #以字符串的形式獲取到函數註釋
若是用內置的模塊,wraps ,就能夠輕鬆解決這個問題,使得全部的還和之前同樣,其中wraps(),中要傳入參數,參數應該與外層裝飾器的形參一致。oop
對於裝飾器,若是你想取消個這裝飾器的功能,如今給出的方法就只能是在裝飾的外面在套一個裝飾器,並設置一個定位符(一個全局變量)來控制其是否執行:spa
control = True def outer(flag): def wrapper(func): def inner(*args,**kwargs): if flag: print('函數執行前') ret = func(*args,**kwargs) print('函數執行後') return ret else: ret = func(*args, **kwargs) return inner return wrapper @outer(control)# shoping = outer(shopping) = wapper(shoping) = inner(shopping) 只是要多一個參數進行判斷 def shopping(num): print(num) return 1 shopping(5)
多個裝飾器進行嵌套,裝飾器的糖的運行是,就近原則,離函數最近的糖先運行code
def wrapper1(func): #func--shopping def inner(*args,**kwargs): print('000函數執行前') ret = func(*args,**kwargs) print('000函數執行後') return ret return inner def wrapper2(func): #func--inner1 def inner(*args,**kwargs): print('111函數執行前') ret = func(*args,**kwargs) #這裏的調用實際上是使用 inner1() 函數 print('111函數執行後') return ret return inner @wrapper2 @wrapper1 def shopping(num): print(num) return 1 shopping(5) ''' 111函數執行前 000函數執行前 5 000函數執行後 111函數執行後 '''
來個做業orm
# 在12 天做業 編寫裝飾器,爲多個函數加上認證功能(用戶的帳號來源於文件), # 要求登入一次成功,後續的函數都無需再輸入用戶和密碼 def wrapper(func): def inner(*args, **kwargs): with open('ver', mode='r+',encoding='utf-8')as f: flag = f.read() if flag: verification = input('>>>').strip() if verification == 'eli123': # f.seek(0) f.truncate(0,) ret = func(*args, **kwargs) return ret else: ret = func(*args, **kwargs) return ret return inner @wrapper def buy(num): print('買了{}個包子'.format(num)) @wrapper def eat(num): print('吃了{}個包子'.format(num)) with open('ver',mode='w',encoding='utf-8') as f: f.write('aaa') buy(3) eat(2)
這裏利用了一個文件,在進行函數前,生成內容,而後文件中有內容時,要求驗證 驗證碼,而後刪除,方便第二次的驗證。blog
# 2.編寫裝飾器,爲多個函數加上記錄調用功能,要求每次調用函數都將被調用的函數名稱寫入文件 from functools import wraps def wrapper(func): wraps(func) def inner(*args, **kwargs): with open('record',mode='a',encoding='utf-8') as f: f.write(func.__name__ + '\n') ret = func(*args, **kwargs) return ret return inner @wrapper def buy(num): print('買了{}個包子'.format(num)) @wrapper def eat(num): print('吃了{}個包子'.format(num)) buy(3) eat(2)
與第一題相比,確實比較容易一點(以後學到時間模塊,能夠加入時間模塊的)ip