亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

一文帶你讀懂python裝飾器

系統(tǒng) 2353 0

文章目錄

  • 前言
  • 一、函數(shù)
    • 1.1 函數(shù)作為對(duì)象傳遞
    • 1.2 函數(shù)作為參數(shù)傳遞
    • 1.3 函數(shù)可嵌套
    • 1.4 返回函數(shù)本身
  • 二、裝飾器
    • 2.1 基礎(chǔ)裝飾器
    • 2.2 帶參裝飾器
    • 2.3 裝飾器自定義參數(shù)
    • 2.4 類裝飾器
    • 2.5 裝飾器嵌套
  • 三、裝飾器的應(yīng)用
  • 四、總結(jié)

前言

我的個(gè)人網(wǎng)站:https://www.gentlecp.com

python中有一個(gè)很經(jīng)典的用法就是裝飾器,它用于在不修改原始函數(shù)的情況下,添加新的功能到原始函數(shù)中,但是這章內(nèi)容比較難以理解,本文就從函數(shù)到裝飾器以及裝飾器在現(xiàn)實(shí)生產(chǎn)中的應(yīng)用舉出樣例,希望能夠幫助大家更好地理解裝飾器到底有何用處

附:文章個(gè)人網(wǎng)站鏈接

一、函數(shù)

談裝飾器前先對(duì)函數(shù)要有一個(gè)深刻理解。在python中,萬物皆對(duì)象,函數(shù)也不例外,我們創(chuàng)建一個(gè)函數(shù)將其打印出來,看看結(jié)果:

            
              
                def
              
              
                func
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is func: {}'
              
              
                .
              
              
                format
              
              
                (
              
              message
              
                )
              
              
                )
              
              
                print
              
              
                (
              
              func
              
                )
              
            
          

一文帶你讀懂python裝飾器_第1張圖片
可以看到返回值為一個(gè)內(nèi)存地址,說明函數(shù)是對(duì)象,既然是對(duì)象,自然可以進(jìn)行賦值傳遞,參數(shù)傳遞操作。

1.1 函數(shù)作為對(duì)象傳遞

看下面的例子:

            
              
                def
              
              
                func
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is func: {}'
              
              
                .
              
              
                format
              
              
                (
              
              message
              
                )
              
              
                )
              
              
    
func_object 
              
                =
              
               func
func_object
              
                (
              
              
                'Hello world'
              
              
                )
              
            
          

在這里插入圖片描述
我們將func這個(gè)對(duì)象直接賦值給func_object,用func_object調(diào)用,結(jié)果成功輸出。說明函數(shù)可作為對(duì)象傳遞

1.2 函數(shù)作為參數(shù)傳遞

看下面的例子:

            
              
                def
              
              
                func_a
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is func_a:{}'
              
              
                .
              
              
                format
              
              
                (
              
              message
              
                )
              
              
                )
              
              
                def
              
              
                func_b
              
              
                (
              
              func
              
                ,
              
              message
              
                )
              
              
                :
              
              
    func
              
                (
              
              message
              
                )
              
              

func_b
              
                (
              
              func_a
              
                ,
              
              
                'Hello world'
              
              
                )
              
            
          

在這里插入圖片描述
我們將func_a作為func_b的參數(shù)傳入func_b中,并在func_b中調(diào)用該函數(shù),打印輸出結(jié)果。說明函數(shù)可以作為參數(shù)傳遞。

1.3 函數(shù)可嵌套

這個(gè)大家應(yīng)該都用過,就是在函數(shù)中有時(shí)候我們會(huì)重復(fù)利用一部分代碼,而這部分代碼在其他地方又不會(huì)用到,就可以將這部分整合成一個(gè)函數(shù),然后進(jìn)行調(diào)用,看下面的例子:

            
              
                def
              
              
                func_root
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                def
              
              
                func_node
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is func_node:{}'
              
              
                .
              
              
                format
              
              
                (
              
              message
              
                )
              
              
                )
              
              
                # 將func_node結(jié)果返回
              
              
                return
              
               func_node
              
                (
              
              message
              
                )
              
                
func_root
              
                (
              
              
                'Hello World'
              
              
                )
              
            
          

在這里插入圖片描述
我們?cè)趂unc_root中又定義了func_node,并在func_root中返回func_node的處理結(jié)果。相當(dāng)于在函數(shù)內(nèi)部調(diào)用了內(nèi)部的函數(shù),說明函數(shù)可嵌套。
舉一個(gè)形象的例子:
老板(func_root)收到外包商一個(gè)項(xiàng)目(‘Hello World’)。
外包商:你幫我打印一下Hello World
老板接收原材料(‘Hello World’)。
老板:我不會(huì)啊,那什么,小C你幫我打印一下。
然后將原材料(‘Hello World’)扔給小C(= =)。
小C:好的老板,打印了Hello World,寫成了報(bào)告。
老板一看:哎喲,不錯(cuò)哦。
然后就將結(jié)果return給了外包商。

1.4 返回函數(shù)本身

前面是內(nèi)部函數(shù)處理了結(jié)果,外部函數(shù)將結(jié)果返回,因?yàn)楹瘮?shù)本身是對(duì)象,自然也可以作為return返回,看下面這個(gè)例子:

            
              
                def
              
              
                func_root
              
              
                (
              
              
                )
              
              
                :
              
              
                def
              
              
                func_node
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is func_node:{}'
              
              
                .
              
              
                format
              
              
                (
              
              message
              
                )
              
              
                )
              
              
                # 將func_node本身返回
              
              
                return
              
               func_node
func_object 
              
                =
              
               func_root
              
                (
              
              
                )
              
              
func_object
              
                (
              
              
                'Hello world'
              
              
                )
              
            
          

同樣用上面的例子:
外包商(func_object):你幫我打印Hello World
老板(func_root):我不會(huì)啊,我把會(huì)打印的人叫來給你用吧,小C你過來一下
外包商:小C,你給我打印Hello World
小C(func_node):print(…)
在代碼中,func_object通過func_root這個(gè)橋梁,獲取到了func_node的地址,這時(shí)候它就可以通過()的形式調(diào)用func_node的功能。

二、裝飾器

2.1 基礎(chǔ)裝飾器

我們先看一個(gè)最基礎(chǔ)的裝飾器:

            
              
                def
              
              
                my_decorator
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "I'm wrapper in my_decorator"
              
              
                )
              
              
        func
              
                (
              
              
                )
              
              
                return
              
               wrapper

@my_decorator

              
                def
              
              
                hello
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'hello world'
              
              
                )
              
              
hello
              
                (
              
              
                )
              
            
          

其中@my_decorator稱為語法糖,其作用等價(jià)于

            
              hello 
              
                =
              
               my_decorator
              
                (
              
              hello
              
                )
              
            
          

在這里插入圖片描述
從結(jié)果可以看出,hello成功執(zhí)行了自己的功能(打印hello world),裝飾器裝飾了hello函數(shù),并在其基礎(chǔ)上添加了功能(打印I’m wrapper in my_decorator)。裝飾器一般有兩層函數(shù),外層my_decorator用于@裝飾在其他函數(shù)上,它返回內(nèi)層函數(shù)(wrapper)的地址,讓被裝飾函數(shù)可以直接獲取到該地址。
前面說過,有了函數(shù)地址,自然可以調(diào)用函數(shù)功能,所以wrapper可以看作被裝飾函數(shù)的加強(qiáng)版函數(shù),在其內(nèi)部必然要調(diào)用被裝飾函數(shù),且添加一些想添加的代碼功能,這使得添加的功能和原始功能互不干擾。
舉個(gè)例子:
小C:我只會(huì)打印hello world,別的我不學(xué),哼~
老板:什么?這么菜怎么完成任務(wù)?不行,我給你個(gè)神器,這個(gè)神器可以自動(dòng)打印I’m wrapper in my_decorator,也不用你學(xué)什么了。但是你要把它戴到頭上。以后我布置打印任務(wù)的時(shí)候,我會(huì)發(fā)命令給這個(gè)神器,這個(gè)神器再提示你怎么做知道嗎?
小C:好的,老板!
老板:神器啊神器,開始打印吧~
神器:打印I’m wrapper in my_decorator完成,小C,打印hello world
小C:好嘞,打印hello world。
有人可能要問了,為什么不直接用一個(gè)函數(shù)wrapper,將hello傳入其中,然后調(diào)用呢?
注意!裝飾器的初衷是不影響原始函數(shù)的代碼和功能,也就是說。假設(shè)原始函數(shù)hello是一個(gè)接口,別人一直用hello作為接口調(diào)用,如果你用wrapper接收hello,那么接口的名稱就要改動(dòng)成wrapper,外面的人并不知道這個(gè),還是用hello調(diào)用,就會(huì)導(dǎo)致出錯(cuò)!而用裝飾器的形式,你發(fā)現(xiàn)沒有,hello接口沒有變,但是新功能已經(jīng)添加進(jìn)去了。

2.2 帶參裝飾器

被裝飾函數(shù)難免會(huì)有參數(shù)傳入,如何將這些參數(shù)一并傳入到裝飾器中呢?看下面的代碼:

            
              
                def
              
              
                my_decorator
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "I'm wrapper in my_decorator"
              
              
                )
              
              
        func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                return
              
               wrapper

@my_decorator

              
                def
              
              
                hello
              
              
                (
              
              name
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'hello world '
              
              
                +
              
              name
              
                )
              
              
    
hello
              
                (
              
              
                'CP'
              
              
                )
              
            
          

這里用到了 args,**kwargs,這樣就可以接收任意數(shù)量或類型的參數(shù),關(guān)于 args,**kwargs網(wǎng)上有很多解釋的文章,這里不多贅述。可以看到成功地進(jìn)行了參數(shù)傳遞。

2.3 裝飾器自定義參數(shù)

前面裝飾器一直是接收被裝飾函數(shù)的參數(shù),那么如果裝飾器自己要定義參數(shù)呢?例如定義裝飾器參數(shù)num,用于指定裝飾器調(diào)用的次數(shù),看下面的代碼:

            
              
                def
              
              
                repeat
              
              
                (
              
              num
              
                )
              
              
                :
              
              
                def
              
              
                my_decorator
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                )
              
              
                :
              
              
                for
              
               i 
              
                in
              
              
                range
              
              
                (
              
              num
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "I'm wrapper in my_decorator"
              
              
                )
              
              
                func
              
                (
              
              
                )
              
              
                return
              
               wrapper
    
              
                return
              
               my_decorator

@repeat
              
                (
              
              
                5
              
              
                )
              
              
                def
              
              
                hello
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'hello world'
              
              
                )
              
              
     
hello
              
                (
              
              
                )
              
            
          

repeat裝飾器傳入了參數(shù)5,用于將他內(nèi)部的函數(shù)執(zhí)行5次
一文帶你讀懂python裝飾器_第2張圖片

2.4 類裝飾器

類也可以作為裝飾器使用,它依賴于函數(shù)__call__,實(shí)際上,每次調(diào)用類的實(shí)例,函數(shù)__call__便執(zhí)行一次。看下面的代碼:

            
              
                class
              
              
                CountClass
              
              
                :
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                ,
              
               func
              
                )
              
              
                :
              
              
        self
              
                .
              
              func 
              
                =
              
               func
        self
              
                .
              
              calls 
              
                =
              
              
                0
              
              
                def
              
              
                __call__
              
              
                (
              
              self
              
                ,
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
        self
              
                .
              
              calls 
              
                +=
              
              
                1
              
              
                print
              
              
                (
              
              
                'calls: {}'
              
              
                .
              
              
                format
              
              
                (
              
              self
              
                .
              
              calls
              
                )
              
              
                )
              
              
                return
              
               self
              
                .
              
              func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              

@CountClass

              
                def
              
              
                hello
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "hello world"
              
              
                )
              
              

hello
              
                (
              
              
                )
              
              
hello
              
                (
              
              
                )
              
            
          

一文帶你讀懂python裝飾器_第3張圖片
本質(zhì)上作用與函數(shù)裝飾器相同,根據(jù)自己的需要選擇用函數(shù)裝飾器還是類裝飾器

2.5 裝飾器嵌套

裝飾器說到底還是函數(shù),因此裝飾器本身也可以被裝飾,看下面的例子:

            
              
                import
              
               functools


              
                def
              
              
                my_decorator1
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is decorator1'
              
              
                )
              
              
        func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                return
              
               wrapper



              
                def
              
              
                my_decorator2
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                'Here is decorator2'
              
              
                )
              
              
        func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                return
              
               wrapper


@my_decorator1
@my_decorator2

              
                def
              
              
                hello
              
              
                (
              
              message
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              message
              
                )
              
              
    
hello
              
                (
              
              
                'hello world'
              
              
                )
              
            
          

一文帶你讀懂python裝飾器_第4張圖片
由結(jié)果可以看出來,執(zhí)行的順序是?decorator1 -> decorator2 -> hello

三、裝飾器的應(yīng)用

裝飾器的應(yīng)用場(chǎng)景有很多,例如登錄驗(yàn)證,日志記錄,合理性檢查等。下面以登錄驗(yàn)證為例:假設(shè)一個(gè)網(wǎng)站有兩個(gè)功能,登錄和評(píng)論,而評(píng)論功能必須要先檢查用戶是否登錄,登錄才能使用否則調(diào)用評(píng)論會(huì)提示需要登錄,看下面代碼:

            
              IS_LOGIN 
              
                =
              
              
                False
              
              
                # 全局變量作為是否登錄的標(biāo)志
              
              
USER 
              
                ,
              
               PWD 
              
                =
              
              
                'CP'
              
              
                ,
              
              
                '123456'
              
              
                # 假設(shè)只有一個(gè)用戶
              
              
                def
              
              
                require_login
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                if
              
               IS_LOGIN
              
                :
              
              
                # 驗(yàn)證通過,可以評(píng)論
              
              
            func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                else
              
              
                :
              
              
                # 驗(yàn)證不通過
              
              
                print
              
              
                (
              
              
                '驗(yàn)證失敗,您未登錄'
              
              
                )
              
              
            login
              
                (
              
              
                )
              
              
                return
              
               wrapper


              
                # 登錄 
              
              
                def
              
              
                login
              
              
                (
              
              
                )
              
              
                :
              
              
                global
              
               IS_LOGIN
    
              
                while
              
              
                True
              
              
                :
              
              
                print
              
              
                (
              
              
                '請(qǐng)輸入登錄用戶名:'
              
              
                )
              
              
        user 
              
                =
              
              
                input
              
              
                (
              
              
                )
              
              
                print
              
              
                (
              
              
                '請(qǐng)輸入密碼:'
              
              
                )
              
              
        pwd 
              
                =
              
              
                input
              
              
                (
              
              
                )
              
              
                # 這里為了簡(jiǎn)便沒有做密碼輸入加密處理,實(shí)際開發(fā)需要做
              
              
                if
              
               user 
              
                ==
              
               USER 
              
                and
              
               pwd 
              
                ==
              
               PWD
              
                :
              
              
                print
              
              
                (
              
              
                '登錄成功'
              
              
                )
              
              
            IS_LOGIN 
              
                =
              
              
                True
              
              
                break
              
              
                else
              
              
                :
              
              
                print
              
              
                (
              
              
                '用戶名或密碼輸入錯(cuò)誤,請(qǐng)重新輸入'
              
              
                )
              
              
                # 評(píng)論功能
              
              
@require_login

              
                def
              
              
                comment
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '歡迎使用評(píng)論功能,請(qǐng)輸入你要評(píng)論的內(nèi)容:'
              
              
                )
              
              
    com 
              
                =
              
              
                input
              
              
                (
              
              
                )
              
              
                print
              
              
                (
              
              
                '你的評(píng)論是:{}'
              
              
                .
              
              
                format
              
              
                (
              
              com
              
                )
              
              
                )
              
              

comment
              
                (
              
              
                )
              
              
comment
              
                (
              
              
                )
              
            
          

運(yùn)行結(jié)果:
一文帶你讀懂python裝飾器_第5張圖片
我們定義兩個(gè)函數(shù)和一個(gè)裝飾器函數(shù),login用于登錄,comment用于評(píng)論,comment被require_login裝飾器裝飾,在require_login裝飾器中會(huì)判斷全局變量IS_LOGIN來檢查用戶是否已經(jīng)登錄,如果登錄則執(zhí)行comment的功能,如果未登錄,則提示用戶進(jìn)行登錄。
第一次調(diào)用comment()提示驗(yàn)證失敗,您未登錄,并讓用戶進(jìn)行登錄操作,登錄成功后,進(jìn)入評(píng)論的核心功能,用戶可以進(jìn)行評(píng)論。
通過上面的例子我們可以發(fā)現(xiàn),comment還是那個(gè)comment,我們并沒有對(duì)其修改,但是讓其使用的時(shí)候多了一層驗(yàn)證,而且這種方式在不改變接口的同時(shí)降低了代碼耦合性,使得程序員維護(hù)成本大大降低,所以是一種非常值得學(xué)習(xí)、掌握的方法。

四、總結(jié)

關(guān)于裝飾器的使用,我大概就總結(jié)了以上內(nèi)容,希望能夠幫助到你更好地理解裝飾器,如果有任何疑問的地方,歡迎在評(píng)論區(qū)留言或私信給我,我會(huì)盡力解答~
建議: 看完文章后一定要自己動(dòng)手嘗試一下才能更好地掌握,不要想當(dāng)然以為自己看了就會(huì)了,動(dòng)手才是將東西變成自己的的唯一途徑!!!


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 欧美大黄大色一级毛片出红 | 成年人黄色小视频 | 中文字幕在线精品视频入口一区 | 激情小视频在线播放免费 | 亚洲第一红杏精品久久 | 久操视频免费观看 | 亚洲视频一区二区 | 最新国产在线视频 | 99精品在线播放 | 国产毛片一区二区三区 | 日韩不卡高清视频 | 91精品国产三级在线观看 | 免费看一级黄色毛片 | 久久爱成人网 | 亚洲欧美日韩成人一区在线 | 日本网站在线播放 | 波多野结衣亚洲一区 | 日日夜夜精品 | 91精品欧美产品免费观看 | 欧美国产成人免费观看永久视频 | jizz中国视频 | 国产福利在线观看永久免费 | 国产成人刺激视频在线观看 | 日韩特级毛片免费观看视频 | 四虎影在线永久免费观看 | 操一操干一干 | 久久青青草视频 | 日韩成人黄色片 | 一级午夜 | 夜夜做夜夜爽 | 国产精品综合久成人 | 久久精品国产色蜜蜜麻豆 | 亚洲网在线 | 免费播放欧美毛片欧美a | 欧美精品久久久久久久久大尺度 | 国产精品视频偷伦精品视频 | 日韩在线观看一区二区三区 | 精品一区二区三区色花堂 | 国产免费播放一区二区 | 奇米色在线 | 亚洲一区中文字幕在线观看 |