小編給大家分享一下Python中裝飾器的使用方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
員工經(jīng)過長期磨合與沉淀,具備了協(xié)作精神,得以通過團隊的力量開發(fā)出優(yōu)質(zhì)的產(chǎn)品。創(chuàng)新互聯(lián)堅持“專注、創(chuàng)新、易用”的產(chǎn)品理念,因為“專注所以專業(yè)、創(chuàng)新互聯(lián)網(wǎng)站所以易用所以簡單”。公司專注于為企業(yè)提供成都網(wǎng)站制作、網(wǎng)站設(shè)計、外貿(mào)網(wǎng)站建設(shè)、微信公眾號開發(fā)、電商網(wǎng)站開發(fā),小程序設(shè)計,軟件按需網(wǎng)站開發(fā)等一站式互聯(lián)網(wǎng)企業(yè)服務(wù)。
裝飾器的使用
來看下面的代碼:
import time import random def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index()
index函數(shù)的作用是程序在隨機睡眠1到5秒之后,打印一句話?,F(xiàn)在想為index函數(shù)添加一個新功能:統(tǒng)計index函數(shù)的運行時間,該怎么做呢??
修改index函數(shù)如下:
import time import random def index(): start_time=time.time() time.sleep(random.randrange(1,5)) print("welcome to index page") end_time=time.time() print("cost time: %s" %(end_time - start_time)) index()
運行程序,執(zhí)行結(jié)果如下:
welcome to index page cost time: 2.000999927520752
可以看到,為index函數(shù)添加新功能確實實現(xiàn)了,但是卻違反了開放封閉原則。在符合開放封閉原則的前提下,如果想為index函數(shù)添加新功能,此時就要使用裝飾器了。
修改代碼
import time import random def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") def timmer(): def inner(): start_time=time.time() index() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner f=timmer() f()
運行程序,查看執(zhí)行結(jié)果
welcome to index page run time: 1.0
從程序執(zhí)行結(jié)果可以看出,index函數(shù)的運行時間已經(jīng)被統(tǒng)計出來了,但是查看源碼可以知道,index函數(shù)的源碼確實沒有被修改,但是index的調(diào)用方式被修改了。而且還有一個問題就是,timmer這個裝飾器只能被用來裝飾index這個函數(shù),如果以后想統(tǒng)計別的函數(shù)的運行時間,又要重新定義別的裝飾器,這樣也太不靈活了。
修改上面的代碼
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index=timmer(index) index()
運行程序,查看程序執(zhí)行結(jié)果
welcome to index page run time: 4.0
可以看到,index函數(shù)的源代碼沒有被修改,index函數(shù)的調(diào)用方式也沒有改變,但是依然為index函數(shù)添加了統(tǒng)計時間的功能,這里使用的就是裝飾器了。
來分析下上面代碼的執(zhí)行流程:
1.導(dǎo)入time和random模塊,定義index函數(shù)和timmer函數(shù)。
2.把原始的index函數(shù)的內(nèi)存地址作為參數(shù)傳給timmer函數(shù)。
3.timmer函數(shù)內(nèi)部嵌套定義一個函數(shù)inner,然后返回inner函數(shù)的內(nèi)存地址。
4.timmer函數(shù)執(zhí)行完成,返回timmer函數(shù)的內(nèi)部函數(shù)inner的內(nèi)存地址,然后把inner的內(nèi)存地址賦值給index變量。
5.index是inner函數(shù)的內(nèi)存地址,index變量加括號運行,實際上就是在運行inner函數(shù)。
6.運行inner函數(shù),定義程序開始時間。
7.執(zhí)行timmer函數(shù)的變量func,在第2步知道,func這個變量就是index的內(nèi)存地址,所以這里實際上是執(zhí)行被裝飾過后的index函數(shù)。
8.index函數(shù)執(zhí)行完成,定義程序的終止時間。
9.統(tǒng)計并打印整個程序的執(zhí)行過程中所花費的時間。
這就是裝飾器裝飾index函數(shù)的執(zhí)行流程。
裝飾器的簡化使用
現(xiàn)在我又有另外一個函數(shù)home,現(xiàn)在我也想統(tǒng)計home函數(shù)的運行時間,可以把代碼修改如下:
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") def home(): time.sleep(random.randrange(1,5)) print("welcome to home page") index=timmer(index) index() home=timmer(home) home()
運行程序,執(zhí)行結(jié)果如下:
welcome to index page run time: 3.0 welcome to home page run time: 4.0
可以看到,每次調(diào)用統(tǒng)計程序運行時間的裝飾器timmer,都要先把被調(diào)用的函數(shù)的函數(shù)名作為參數(shù)傳給timmer裝飾器,然后再把timmer裝飾器的執(zhí)行結(jié)果賦值給被調(diào)用的函數(shù)名本身,最后才能調(diào)用被裝飾的函數(shù),太麻煩了有沒有??
其實python中的裝飾器可以簡化成下面的格式:
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner @timmer def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") @timmer def home(): time.sleep(random.randrange(1,5)) print("welcome to home page") index() home()
程序執(zhí)行結(jié)果:
welcome to index page run time: 2.0 welcome to home page run time: 4.0
可以看出,使用@加裝飾器名添加到被裝飾對象的上方的方式也可以為一個函數(shù)添加裝飾器中定義的功能。
多個裝飾器的定義與調(diào)用
在上面的例子里,定義并調(diào)用了一個統(tǒng)計程序運行時間的裝飾器timmer,如果現(xiàn)在想為index函數(shù)添加一個用戶認證的功能,可以定義一個名為auth的裝飾器。
import time import random def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @auth def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index()
運行程序:
Input your username>>>:abcd # 先輸入錯誤的用戶名和密碼 Input your password>>>:1234 login error # 提示用戶輸入錯誤,登錄失敗 Input your username>>>:abcd # 讓用戶再次輸入用戶名和密碼 Input your password>>>:abcd1234 login successful # 登錄成功 welcome to index page # 執(zhí)行index函數(shù)
從程序執(zhí)行結(jié)果可以看出,用戶登錄密碼驗證的裝飾器auth已經(jīng)定義并被成功調(diào)用了。
如果想為index函數(shù)添加用戶認證的功能,又想統(tǒng)計index函數(shù)執(zhí)行時間的功能,在使用裝飾器的情況下該怎么調(diào)用呢?
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @timmer @auth def index(): time.sleep(2) print("welcome to index page") index()
在上面的代碼里,為index函數(shù)添加了兩個裝飾器,現(xiàn)在有一個問題,就是這兩個裝飾器究竟哪個先被調(diào)用,哪個后被調(diào)用呢??
來分析一下,如果timmer裝飾器先被調(diào)用,那么程序就會先執(zhí)行timmer裝飾器,然后再執(zhí)行auth裝飾器,提示輸入用戶名和密碼,這樣一來timmer裝飾器統(tǒng)計的時間就會包括輸入用戶名和密碼的時間,這個時間會遠遠大于index函數(shù)睡眠的2秒種;如果auth裝飾器先被調(diào)用,timmer裝飾器后被調(diào)用,那么timmer裝飾器統(tǒng)計的運行時間就應(yīng)該只包括index函數(shù)的執(zhí)行時間值應(yīng)該在2秒多一點點的時間范圍內(nèi)。
運行程序,先輸入錯誤的用戶名和密碼以使用程序的執(zhí)行時間加長。
Input your username>>>:abcd Input your password>>>:abcd login error Input your username>>>:abcd Input your password>>>:abcd1234 login successful welcome to index page run time: 12.759000062942505
從程序的執(zhí)行結(jié)果可以知道,程序是先運行timmer裝飾器,然后才運行auth裝飾器,所以timmer統(tǒng)計的時間就包括了用戶認證的時間,所以timmer統(tǒng)計到的程序運行時間遠遠大于index睡眠的2秒鐘。
所以這里得出一個結(jié)論:
當(dāng)一個函數(shù)同時被兩個裝飾器裝飾時,加上函數(shù)最上面的裝飾器先執(zhí)行,加在下面的裝飾器先裝飾。
把上面例子里的timmer裝飾器和auth裝飾器位置互換一下。
import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def auth(func): def wrapper(): while True: user=input("Input your username>>>:").strip() pwd=input("Input your password>>>:").strip() if user== "abcd" and pwd == "abcd1234": print("login successful") func() break else: print("login error") return wrapper @auth @timmer def index(): time.sleep(2) print("welcome to index page") index()
運行index函數(shù),依然先輸入錯誤的用戶名和密碼,增加用戶認證的時間。
Input your username>>>:abcd Input your password>>>:abcd login error Input your username>>>:abcd Input your password>>>:abcd1234 login successful welcome to index page run time: 2.0
可以看到,這次timmer統(tǒng)計到的時間只包含index函數(shù)的運行時間,不包含用戶進行認證的時間。
來分析一下上面例子中,index函數(shù)被timmer裝飾器和auth裝飾器裝飾的代碼裝飾流程。
@auth # index=auth(timmer(index)) @timmer # index=timmer(index) def index(): time.sleep(2) print("welcome to index page")
在上面得出結(jié)論,一個函數(shù)同時被兩個裝飾器時,加在下面的裝飾器先裝飾:
1.timmer裝飾器裝飾原始的index,可以寫成:index=timmer(index)。
2.在timmer裝飾器中,timmer裝飾器實際上是返回inner的內(nèi)存地址,所以在這里,index=inner。
3.timmer裝飾器裝飾完成后,由auth裝飾器來裝飾,此時可以寫成index=auth(index)。
4.這里auth括號里的index已經(jīng)不再是原始index函數(shù),而是已經(jīng)被timmer裝飾過后的index了,所以index=auth(timmer(index))。
5.又因為timmer裝飾的結(jié)果等于inner函數(shù)的內(nèi)存地址,所以:index=auth(inner)。
至此,兩個裝飾器的裝飾過程已經(jīng)知道了,來看程序的執(zhí)行過程:
6.程序先執(zhí)行auth裝飾器,進入用戶認證,請用戶輸入用戶名和密碼。
7.用戶輸入正確的用戶名和密碼后,開始執(zhí)行func函數(shù),也已經(jīng)上面分析的inner函數(shù)。
8.timmer裝飾器先定義程序的開始運行時間,然后運行func函數(shù),也就是原生的index函數(shù)。
9.index函數(shù)先睡眠2秒,然后執(zhí)行print語句,再定義程序的結(jié)束時間。
10.最后統(tǒng)計并打印程序的運行時間,至此程序運行完畢。
所以這里用戶輸入用戶名和密碼的時間不會被timmer裝飾器統(tǒng)計在內(nèi)。
以上是Python中裝飾器的使用方法的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
新聞名稱:Python中裝飾器的使用方法
網(wǎng)頁路徑:http://www.rwnh.cn/article18/ihjgdp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設(shè)、全網(wǎng)營銷推廣、靜態(tài)網(wǎng)站、企業(yè)建站、網(wǎng)站改版、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)