中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

Python中裝飾器的使用方法

小編給大家分享一下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)

綿陽服務(wù)器托管
突泉县| 乡宁县| 淮阳县| 邮箱| 搜索| 阿拉善盟| 蒙阴县| 会昌县| 乐平市| 开封县| 安图县| 阳曲县| 龙海市| 大荔县| 潼南县| 石门县| 富宁县| 来宾市| 彰武县| 钟祥市| 泾阳县| 美姑县| 竹北市| 富川| 颍上县| 葫芦岛市| 昌都县| 宜君县| 梁河县| 刚察县| 漠河县| 绥中县| 买车| 扶绥县| 隆化县| 衡南县| 西林县| 垣曲县| 达拉特旗| 沽源县| 奎屯市|