1、裝飾器介紹與簡單實現python
什麼是裝飾器
器:指的是具有某一功能的工具
裝飾:指的是爲被裝飾器對象添加新功能
裝飾器就是用來爲被裝飾器對象添加新功能的工具
注意:裝飾器自己能夠是任意可調用對象,被裝飾器的對象也能夠是任意可調用對象
2. 爲什麼要用裝飾器
開放封閉原則:封閉指的是對修改封閉,對擴展開放
裝飾器的實現必須遵循兩大原則:
1. 不修改被裝飾對象的源代碼
2. 不修改被裝飾器對象的調用方式
裝飾器的目標:就是在遵循1和2原則的前提下爲被裝飾對象添加上新功能
3. 怎麼用裝飾器mysql
import time def index(): print('welcome to index page') time.sleep(2) 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() #wrapper的內存地址() ------------------------------------- welcome to index page run time is 2.0003037452697754
例1:(無參裝飾器)sql
import time def outter(func): # func=最原始那個index的內存地址 def wrapper(): start=time.time() func() #最原始的那個index的內存地址() stop=time.time() print('run time is %s' %(stop - start)) return wrapper #@outter # 語法糖 等於 但 語法格式是 index=outer(index)要寫在被裝飾函數的下面 def index(): print('welcome to index page') time.sleep(3) index = outter(index) #沒有語法糖的須要寫在裝飾器與函數下面 index()
例二、(無參裝飾器)緩存
import time def outter(func): # func 表示的是Index 的函數當參數來用 def wrapper(*args,**kwargs): start=time.time() func(*args,**kwargs) # 這裏其實用的就是index() stop=time.time() print('run time is %s' %(stop - start)) return wrapper @outter # 有語法糖必須寫在裝飾器與函數的中間 def index(x): # 例如:(寫活,不要寫死,例如要傳遞參數x) 若是函數中須要傳遞參數,那麼就須要在裝飾器中接受加參數來接受 print('welcome to index page') time.sleep(2) index(1)
2、裝飾器升級版閉包
import time def index(): print('welcome to index page') time.sleep(3) def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 def timmer(func): #func=最原始那個home函數的內地址 def wrapper(*args,**kwargs): #args=('egon',) kwargs={} start=time.time() res=func(*args,**kwargs) #最原始那個home函數的內地址('egon') stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper # index=timmer(index) index() home=timmer(home) #home=outter(最原始那個home函數的內地址) #home=wrapper函數的內地址 res=home('egon') # res=wrapper函數的內地址('egon') print(res) --------------------------------------------------------------------------------------------------- welcome to index page welcome egon to home page run time is 2.000187635421753 123
3、裝飾器的語法糖app
# 裝飾器的語法糖:在被裝飾對象正上方單獨一行寫@裝飾器的名字
# 運行原理:ide
python解釋器一旦運行到@裝飾器的名字,就會調用裝飾器,而後將被裝飾函數的內存地址看成參數
#傳給裝飾器,最後將裝飾器調用的結果賦值給原函數名函數
import time def timmer(func): #func=最原始那個home函數的內地址 def wrapper(*args,**kwargs): #args=('egon',) kwargs={} start=time.time() res=func(*args,**kwargs) #最原始那個home函數的內地址('egon') stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper @timmer #index=timmer(index) def index(): print('welcome to index page') time.sleep(3) @timmer #home=timmer(home) def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 index() res=home('egon') # res=wrapper函數的內地址('egon') print(res)
import time # 裝飾器模板 def outter(func): def wrapper(*args,**kwargs): #在調用函數前加功能 res=func(*args,**kwargs) #調用被裝飾的\也就是最原始的那個函數 #在調用函數後加功能 return res return wrapper @outter #index=outter(index) #index=wrapper def index(): print('welcome to index page') time.sleep(3) index()
4、練習認證功能裝飾器工具
import time def auth(func): def wrapper(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 調用最原始的那個/也就是被裝飾的那個函數 return res else: print('username or password error') return wrapper @auth # index=auth(index) #index=wrapper def index(): print('welcome to index page') time.sleep(3) index() #wrapper()
5、疊加多個裝飾器url
import time def timmer(func): #func=wrapper2 def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): #func=最原始的那個index的內存地址 def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 調用最原始的那個/也就是被裝飾的那個函數 return res else: print('username or password error') return wrapper2 # 解釋@語法的時候是自下而上運行 # 而執行裝飾器內的那個wrapper函數時的是自上而下 @timmer # index=timmer(wrapper2) #index=wrapper1 @auth # index=auth(最原始的那個index的內存地址) #index=wrapper2 def index(): print('welcome to index page') time.sleep(2) index() #wrapper1()
import time def timmer(func): print('timmer') def wrapper1(*args,**kwargs): start=time.time() res=func(*args,**kwargs) #res=wrapper2(*args,**kwargs) stop=time.time() print('run time is %s' %(stop - start)) return res return wrapper1 def auth(func): print('auth') def wrapper2(*args,**kwargs): inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') res=func(*args,**kwargs) # 調用最原始的那個/也就是被裝飾的那個函數 return res else: print('username or password error') return wrapper2 @auth # index=auth(wrapper1) #index=wrapper2 @timmer #timmer(最原始的index)返回wrapper1 def index(): print('welcome to index page') time.sleep(3) index() #wrapper2() ''' outter2 outter1 wrapper1 wrapper2 '''
6、有參裝飾器
import time current_user={'username':None} # 補充:全部的數據類型的值自帶布爾值,能夠直接看成條件去用,只須要記住布爾值爲假的那一些值便可(0,空,None) def login(engine='file'): #engine='mysql' def auth(func): #func=最原始那個index的內存地址 def wrapper(*args,**kwargs): ##若是被裝飾的函數有參數須要傳遞,那麼這裏也須要接收傳遞的參數 if current_user['username']: print('已經登陸過了,無需再次登錄') res=func(*args,**kwargs) return res if engine == 'file': inp_user = input('please input your username: ').strip() inp_pwd = input('please input your password: ').strip() if inp_user == 'egon' and inp_pwd == '123': print('login successfull') current_user['username']=inp_user # 在登錄成功以後馬上記錄登陸狀態 res=func(*args,**kwargs) # res=最原始那個index的內存地址(*args,**kwargs) ## 這裏是被裝飾函數須要傳遞參數時,也須要加(*args,**kwargs) return res else: print('username or password error') elif engine == 'mysql': print('基於mysql的認證機制') elif engine == 'ldap': print('基於ldap的認證機制') else: print('沒法識別的認證源') return wrapper return auth @login('file') #@auth # index=auth(最原始那個index的內存地址) #index=wrapper def index(): print('welcome to index page') time.sleep(3) @login('file') def home(name): print('welcome %s to home page' %name) time.sleep(2) return 123 index() #wrapper() res=home('egon') print(res)
# 有參裝飾器的模板
def outter1(x,y,z): def outter2(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper return outter2
# 無參裝飾器的模板
def outter(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) return res return wrapper
裝飾器補充:
#wraps裝飾器應該加到裝飾器最內層的函數上 from functools import wraps import time def deco(func): @wraps(func) def wrapper(*args, **kwargs): res = func(*args, **kwargs) return res # wrapper.__name__=func.__name__ # wrapper.__doc__=func.__doc__ return wrapper @deco #index=deco(index) #index=wrapper函數的內存地址 def index(): """ index 功能 """ print('welcome to index page') time.sleep(3) print(index.__name__) print(help(index)) #index.__doc__ index() print(index.__name__) print(index.__doc__) --------------------------------------------------------------------------------- index Help on function index in module __main__: index() index 功能 None welcome to index page index index 功能
做業:
今日做業: 默寫: 開閉原則 什麼樣的函數稱爲閉包 python中什麼是裝飾器 裝飾器的兩個原則 一:編寫函數,(函數執行的時間是隨機的) 二:編寫裝飾器,爲函數加上統計時間的功能 三:編寫裝飾器,爲函數加上認證的功能 四:編寫裝飾器,爲多個函數加上認證的功能(用戶的帳號密碼來源於文件),要求登陸成功一次,後續的函數都無需再輸入用戶名和密碼 注意:從文件中讀出字符串形式的字典,能夠用eval('{"name":"egon","password":"123"}')轉成字典格式 五:編寫裝飾器,爲多個函數加上認證功能,要求登陸成功一次,在超時時間內無需重複登陸,超過了超時時間,則必須從新登陸 六:編寫下載網頁內容的函數,要求功能是:用戶傳入一個url,函數返回下載頁面的結果 七:爲題目五編寫裝飾器,實現緩存網頁內容的功能: 具體:實現下載的頁面存放於文件中,若是文件內有值(文件大小不爲0),就優先從文件中讀取網頁內容,不然,就去下載,而後存到文件中 擴展功能:用戶能夠選擇緩存介質/緩存引擎,針對不一樣的url,緩存到不一樣的文件中 八:還記得咱們用函數對象的概念,製做一個函數字典的操做嗎,來來來,咱們有更高大上的作法,在文件開頭聲明一個空字典,而後在每一個函數前加上裝飾器,完成自動添加到字典的操做 九 編寫日誌裝飾器,實現功能如:一旦函數f1執行,則將消息2017-07-21 11:12:11 f1 run寫入到日誌文件中,日誌文件路徑能夠指定 注意:時間格式的獲取 import time time.strftime('%Y-%m-%d %X')