欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

一文帶你讀懂python裝飾器

系統 2219 0

文章目錄

  • 前言
  • 一、函數
    • 1.1 函數作為對象傳遞
    • 1.2 函數作為參數傳遞
    • 1.3 函數可嵌套
    • 1.4 返回函數本身
  • 二、裝飾器
    • 2.1 基礎裝飾器
    • 2.2 帶參裝飾器
    • 2.3 裝飾器自定義參數
    • 2.4 類裝飾器
    • 2.5 裝飾器嵌套
  • 三、裝飾器的應用
  • 四、總結

前言

我的個人網站:https://www.gentlecp.com

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

附:文章個人網站鏈接

一、函數

談裝飾器前先對函數要有一個深刻理解。在python中,萬物皆對象,函數也不例外,我們創建一個函數將其打印出來,看看結果:

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

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

1.1 函數作為對象傳遞

看下面的例子:

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

在這里插入圖片描述
我們將func這個對象直接賦值給func_object,用func_object調用,結果成功輸出。說明函數可作為對象傳遞

1.2 函數作為參數傳遞

看下面的例子:

            
              
                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的參數傳入func_b中,并在func_b中調用該函數,打印輸出結果。說明函數可以作為參數傳遞。

1.3 函數可嵌套

這個大家應該都用過,就是在函數中有時候我們會重復利用一部分代碼,而這部分代碼在其他地方又不會用到,就可以將這部分整合成一個函數,然后進行調用,看下面的例子:

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

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

1.4 返回函數本身

前面是內部函數處理了結果,外部函數將結果返回,因為函數本身是對象,自然也可以作為return返回,看下面這個例子:

            
              
                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):我不會啊,我把會打印的人叫來給你用吧,小C你過來一下
外包商:小C,你給我打印Hello World
小C(func_node):print(…)
在代碼中,func_object通過func_root這個橋梁,獲取到了func_node的地址,這時候它就可以通過()的形式調用func_node的功能。

二、裝飾器

2.1 基礎裝飾器

我們先看一個最基礎的裝飾器:

            
              
                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稱為語法糖,其作用等價于

            
              hello 
              
                =
              
               my_decorator
              
                (
              
              hello
              
                )
              
            
          

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

2.2 帶參裝飾器

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

            
              
                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,這樣就可以接收任意數量或類型的參數,關于 args,**kwargs網上有很多解釋的文章,這里不多贅述。可以看到成功地進行了參數傳遞。

2.3 裝飾器自定義參數

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

            
              
                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裝飾器傳入了參數5,用于將他內部的函數執行5次
一文帶你讀懂python裝飾器_第2張圖片

2.4 類裝飾器

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

            
              
                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張圖片
本質上作用與函數裝飾器相同,根據自己的需要選擇用函數裝飾器還是類裝飾器

2.5 裝飾器嵌套

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

            
              
                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張圖片
由結果可以看出來,執行的順序是?decorator1 -> decorator2 -> hello

三、裝飾器的應用

裝飾器的應用場景有很多,例如登錄驗證,日志記錄,合理性檢查等。下面以登錄驗證為例:假設一個網站有兩個功能,登錄和評論,而評論功能必須要先檢查用戶是否登錄,登錄才能使用否則調用評論會提示需要登錄,看下面代碼:

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


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

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

comment
              
                (
              
              
                )
              
              
comment
              
                (
              
              
                )
              
            
          

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

四、總結

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


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 精品国产中文字幕 | 一级片性 | 中文字幕免费在线观看动作大片 | 亚洲午夜精品一区二区三区 | 国产综合成色在线视频 | 久久精品小视频 | 精品国产欧美一区二区 | 2019国产精品| h视频在线免费 | 日本三级网 | 久久艹免费视频 | 日日碰狠狠添天天爽五月婷 | av免费在线观看网站 | 91短视频社区在线观看 | 一区在线视频 | 欧美日韩一区二区三区四区五区 | 激情啪啪网站 | 天天综合网在线观看视频 | 日韩深夜视频 | 日韩中文字幕在线播放 | 久久久久久亚洲精品 | 国产三级一区二区三区 | 美女在线视频一区二区 | 热99这里只有精品 | 亚洲伊人色一综合网 | 成人三级视频 | 一级肉体aa电影 | 97碰碰碰| 日日摸夜夜摸狠狠摸日日碰夜夜做 | 午夜小视频在线播放 | 国产换爱交换乱理伦片 | 日本精品视频 | 午夜九九九 | 国产精品九九久久一区hh | 一区二区三区视频 | 午夜亚洲国产成人不卡在线 | 无遮挡又黄又爽又色的动态图1000 | 亚洲久久视频 | 好吊色欧美一区二区三区四区 | 性生潮久久久不久久久久 | 亚洲国产三级 |