目錄python
器是指工具,而程序中的函數就是具有某一功能的工具,因此裝飾器指的是爲裝飾器對象額外對象添加額外功能,所以定義裝飾器就是定義一個函數,只不過該函數的功能是用來爲其餘函數添加額外功能的。mysql
須要注意的是:sql
若是咱們已經上線 了一個項目,須要修改某一個方法,可是咱們不想修改方法的使用方法,這個時候可使用裝飾器。由於軟件的維護應該遵循開發封閉原則,即軟件于丹上線運行後,軟件的維護對修改原碼是封閉的,對擴展功能指的是開發的。mongodb
裝飾器的實現必須遵照倆大規則:閉包
裝飾器其實就是在遵照以上倆個原則的前提下被裝飾對象添加新功能。app
改變源代碼函數
import time def index(): start = time.time() print('welcome to index') time.sleep(1) end = time.time() print('運行時間:', end - start) index() #輸出: welcome to index 運行時間: 1.0003464221954346
編寫重複代碼工具
import time def index(): print('welcome to index') time.sleep(1) def f2(): print('welcome to f2') time.sleep(1) start = time.time() index() end = time.time() print('運行時間:', end - start) start = time.time() f2() end = time.time() print('運行時間:', end - start) #輸出: welcome to index 運行時間: 1.0001671314239502 welcome to f2 運行時間: 1.0003397464752197
第一種傳參方式:改變調用方式code
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): start = time.time() func() end = time.time() print('運行時間:', end - start) time_count(index) #輸出: welcome to index 運行時間: 1.0005521774291992
第二種傳參方式:包給函數-外包對象
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): def wrapper(): start = time.time() func() end = time.time() print('運行時間:', end - start) return wrapper index = time_count(index) index() #輸出: welcome to index 運行時間: 1.0000648498535156
上述的裝飾器,最後調用index()的時候,實際上是在調用wrapper(),所以若是原始的index()有返回值的時候,wrapper()函數的返回值應該和index()的返回值相同,也就是說,咱們須要同步原始的index()和wrapper()方法的返回值。
import time def index(): print('welcome to index') time.sleep(1) return 123 def time_count(func): def wrapper(): start = time.time() res = func() end = time.time() print('運行時間:', end - start) return res return wrapper index = time_count(index) res = index() print(res) #輸出: welcome to index 運行時間: 1.0007765293121338 123
若是原始的index()方法須要傳參,那麼咱們以前的裝飾器是沒法實現該功能的,因爲有wrapper()=index(),因此給wrapper()方法傳參便可。
import time def home(name): print(f'welcome {name} to home page') time.sleep(1) return name def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f'{func} time is {end - start}') return res return wrapper home = time_count(home) res = home('chen') print('res:', res) #輸出: welcome chen to home page <function home at 0x000002085D50B0D8> time is 1.0006473064422607 res: chen
在被裝飾函數正上方,而且是單獨一行寫上@裝飾器名
import time def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f'{func} time is {end - start}') return res return wrapper @time_count def home(name): print(f'welcome {name} to home page') time.sleep(1) return name @time_count def index(): print('welcome to index') time.sleep(1) return 123 res = home('egon') print(f"res:{res}") #輸出: welcome egon to home page <function home at 0x00000203FABAC948> time is 1.0005333423614502 res:egon
def func(): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
無參裝飾器只套了兩層,有參裝飾器是套三層。
#登錄註冊的裝飾器 import time current_user = {'username': None} def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() if user == 'chen' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') return wrapper @login def home(name): print(f'welcome {name} to home page') time.sleep(1) return name @login def index(): print('welcome to index') time.sleep(1) return 123 res = index() #輸出: username:chen password:123 login successful welcome to index
對於上面的登錄註冊,咱們把用戶登錄成功的信息寫入內存文檔中,可是在工業在,內存信息能夠存在文本中,mysql中,mongodb中,可是咱們只能讓用戶信息來自於file
的用戶能夠認證,所以咱們能夠改寫上述的裝飾器。
import time current_user = {'username': None} def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() engine = 'file' if engine == 'file': print('base of file') if user == 'chen' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql') elif engine == 'mongodb': print('base of mongodb') else: print('default') return wrapper @login def home(name): print(f'welcome {name} to home page') time.sleep(1) @login def index(): print('welcome to index') time.sleep(1) res = index() #輸出: username:chen password:123 base of file login successful welcome to index
三層簡單實例
def f1(y): def f2(): x = 1 def f3(): print('x:', x) print('y:', y) return f3 return f2 f2 = f1(2) f3 = f2() f3() #輸出: x: 1 y: 2
如今須要修改原來需求,須要判斷用戶動態的獲取用戶密碼的方式,若是是file
類型的咱們則讓用戶進行認證,所以咱們須要使用,有參裝飾器。
import time current_user = {'username': None} def auth(engine='file'): def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username:').strip() pwd = input('password:').strip() if engine == 'file': print('base of file') if user == 'chen' and pwd == '123': print('登錄成功') current_user['username'] = user res = func(*args, **kwargs) return res else: print('用戶密碼或者用戶名錯誤') elif engine == 'mysql': print('base of mysql') elif engine == 'mongodb': print('base of mongodb') else: print('please base of file') return wrapper return login @auth(engine='mysql') def home(name): print(f'welcome {name} to home page') time.sleep(1) @auth(engine='file') def index(): print('welcome to index') time.sleep(1) res = index() #輸出: username:chen password:123 base of file 登錄成功 welcome to index
因爲倆層的裝飾器,參數必須得固定定位func
,可是三層的裝飾器解除了這個限制,咱們不單單可使用上述單個參數的三層裝飾器,多個參數的只須要在三層裝飾器中多家幾個參數便可,也就是說裝飾器三層便可,多加無用。
def outter1(func): # func = wrapper2 def wrapper1(*args, **kwargs): # wrapper是將來要運行的函數 print('------------') res = func(*args, **kwargs) # func是被裝飾的函數 # wrapper2 print('------------') return res return wrapper1 def outter2(func): # func = index def wrapper2(*args, **kwargs): # wrapper是將來要運行的函數 print('11111111111111') res = func(*args, **kwargs) # func是被裝飾的函數 # index() print('11111111111111') return res return wrapper2 # @outter1 # index = outter1(index) # @outter2 # index = outter2(index) # 先運行最下面的裝飾器 # # index def index(): print('index') # index從新定義的index = outter2(index 真正的index) index = outter2(index) # index = wrapper2 # index再一次從新定義的index = outter1(index從新定義的index,即wrapper2) index = outter1(index) # index = wrapper1 index() # wrapper1() #輸出: ------------ 11111111111111 index 11111111111111 ------------
def outter(func): def wrapper(*args,**kwargs): #加功能 res = func(*args,**kwargs) return res return wrapper
主要是用來給 倆層裝飾器添加參數
def sanceng(engine): def outter(func): def wrapper(*args, **kwargs): # 加功能 print(engine) res = func(*args, **kwargs) return res return wrapper return outter @sanceng('file') def shopping(): print('shopping') shopping() #輸出:file shopping