日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

python 裝飾函數 和 閉包 基礎總結。

系統 2195 0

一、 裝飾函數

(1)概念:

裝飾器本質上是一個 Python 函數或類,它可以讓其他函數或類在不需要做任何代碼修改的前提下 增加額外功能 ,裝飾器的返回值也是一個 函數/類對象 。它經常用于有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景,裝飾器是解決這類問題的絕佳設計。有了裝飾器,我們就可以抽離出大量與函數功能本身無關的雷同代碼到裝飾器中并繼續重用。概括的講,裝飾器的作用就是 為已經存在的對象添加額外的功能

使用方法:

  1. 先定義一個裝飾器(帽子)
  2. 再定義你的業務函數或者類(人)
  3. 最后把這裝飾器(帽子)扣在這個函數(人)頭上

(2)實例:

  1. 日志打印器
            
              
                # 這是裝飾器函數,參數 func 是被裝飾的函數
              
              
                def
              
              
                logger
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '主人,我準備開始執行:{} 函數了:'
              
              
                .
              
              
                format
              
              
                (
              
              func
              
                .
              
              __name__
              
                )
              
              
                )
              
              
                # 真正執行的是這行。
              
              
        func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
                print
              
              
                (
              
              
                '主人,我執行完啦。'
              
              
                )
              
              
                return
              
               wrapper
@logger  
              
                # =》 add = logger(add)
              
              
                def
              
              
                add
              
              
                (
              
              x
              
                ,
              
               y
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '{} + {} = {}'
              
              
                .
              
              
                format
              
              
                (
              
              x
              
                ,
              
               y
              
                ,
              
               x
              
                +
              
              y
              
                )
              
              
                )
              
            
          

執行:
在這里插入圖片描述
2. 時間計時器

            
              
                # 這是裝飾函數
              
              
                def
              
              
                timer
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
                :
              
              
        t1
              
                =
              
              time
              
                .
              
              time
              
                (
              
              
                )
              
              
                # 這是函數真正執行的地方
              
              
        func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
        t2
              
                =
              
              time
              
                .
              
              time
              
                (
              
              
                )
              
              
                # 計算下時長
              
              
        cost_time 
              
                =
              
               t2
              
                -
              
              t1 
        
              
                print
              
              
                (
              
              
                "花費時間:{}秒"
              
              
                .
              
              
                format
              
              
                (
              
              cost_time
              
                )
              
              
                )
              
              
                return
              
               wrapper

              
                import
              
               time

@timer

              
                def
              
              
                want_sleep
              
              
                (
              
              sleep_time
              
                )
              
              
                :
              
              
    time
              
                .
              
              sleep
              
                (
              
              sleep_time
              
                )
              
              

want_sleep
              
                (
              
              
                10
              
              
                )
              
              
                #花費時間:10.000298261642456秒
              
            
          
  1. 帶參數的函數裝飾器
            
              
                def
              
              
                say_hello
              
              
                (
              
              contry
              
                )
              
              
                :
              
              
                def
              
              
                wrapper
              
              
                (
              
              func
              
                )
              
              
                :
              
              
                def
              
              
                deco
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                if
              
               contry 
              
                ==
              
              
                "china"
              
              
                :
              
              
                print
              
              
                (
              
              
                "你好!"
              
              
                )
              
              
                elif
              
               contry 
              
                ==
              
              
                "america"
              
              
                :
              
              
                print
              
              
                (
              
              
                'hello.'
              
              
                )
              
              
                else
              
              
                :
              
              
                return
              
              
                # 真正執行函數的地方
              
              
            func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                return
              
               deco
    
              
                return
              
               wrapper


              
                # 小明,中國人
              
              
@say_hello
              
                (
              
              
                "china"
              
              
                )
              
              
                def
              
              
                xiaoming
              
              
                (
              
              
                )
              
              
                :
              
              
                pass
              
              
                # jack,美國人
              
              
@say_hello
              
                (
              
              
                "america"
              
              
                )
              
              
                def
              
              
                jack
              
              
                (
              
              
                )
              
              
                :
              
              
                pass
              
            
          

python 裝飾函數 和 閉包 基礎總結。_第1張圖片
4. 不帶參數的類裝飾器
基于類裝飾器的實現,必須實現 call 和 __init__兩個內置函數。
init :接收被裝飾函數
call :實現裝飾邏輯。

            
              
                class
              
              
                logger
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                ,
              
               func
              
                )
              
              
                :
              
              
        self
              
                .
              
              func 
              
                =
              
               func

    
              
                def
              
              
                __call__
              
              
                (
              
              self
              
                ,
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "[INFO]: the function {func}() is running..."
              
              \
            
              
                .
              
              
                format
              
              
                (
              
              func
              
                =
              
              self
              
                .
              
              func
              
                .
              
              __name__
              
                )
              
              
                )
              
              
                return
              
               self
              
                .
              
              func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              

@logger

              
                def
              
              
                say
              
              
                (
              
              something
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "say {}!"
              
              
                .
              
              
                format
              
              
                (
              
              something
              
                )
              
              
                )
              
              

say
              
                (
              
              
                "hello"
              
              
                )
              
              
                #[INFO]: the function say() is running...
              
              
                #say hello!
              
            
          
  1. 帶參數的類裝飾器
    上面不帶參數的例子,你發現沒有,只能打印INFO級別的日志,正常情況下,我們還需要打印DEBUG WARNING等級別的日志。這就需要給類裝飾器傳入參數,給這個函數指定級別了。

帶參數和不帶參數的類裝飾器有很大的不同。

init :不再接收被裝飾函數,而是接收傳入參數。
call :接收被裝飾函數,實現裝飾邏輯。

            
              
                class
              
              
                logger
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                ,
              
               level
              
                =
              
              
                'INFO'
              
              
                )
              
              
                :
              
              
        self
              
                .
              
              level 
              
                =
              
               level

    
              
                def
              
              
                __call__
              
              
                (
              
              self
              
                ,
              
               func
              
                )
              
              
                :
              
              
                # 接受函數
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "[{level}]: the function {func}() is running..."
              
              \
                
              
                .
              
              
                format
              
              
                (
              
              level
              
                =
              
              self
              
                .
              
              level
              
                ,
              
               func
              
                =
              
              func
              
                .
              
              __name__
              
                )
              
              
                )
              
              
            func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kwargs
              
                )
              
              
                return
              
               wrapper  
              
                #返回函數
              
              

@logger
              
                (
              
              level
              
                =
              
              
                'WARNING'
              
              
                )
              
              
                def
              
              
                say
              
              
                (
              
              something
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                "say {}!"
              
              
                .
              
              
                format
              
              
                (
              
              something
              
                )
              
              
                )
              
              

say
              
                (
              
              
                "hello"
              
              
                )
              
              
                #[WARNING]: the function say() is running...
              
              
                #say hello!
              
            
          
  1. 內置裝飾器:property
            
            
          
  1. 如果 decorator本身需要傳入參數 ,那就需要編寫一個返回decorator的高階函數。(即再嵌套一個decorator函數):
            
              
                def
              
              
                log
              
              
                (
              
              text
              
                )
              
              
                :
              
              
                def
              
              
                decorator
              
              
                (
              
              func
              
                )
              
              
                :
              
              
        @functools
              
                .
              
              wraps
              
                (
              
              func
              
                )
              
              
                #把原始函數的__name__等屬性復制到wrapper()函數中
              
              
                def
              
              
                wrapper
              
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '%s %s():'
              
              
                %
              
              
                (
              
              text
              
                ,
              
               func
              
                .
              
              __name__
              
                )
              
              
                )
              
              
                return
              
               func
              
                (
              
              
                *
              
              args
              
                ,
              
              
                **
              
              kw
              
                )
              
              
                return
              
               wrapper
    
              
                return
              
               decorator

@log
              
                (
              
              
                'execute'
              
              
                )
              
              
                #now = log('execute')(now)
              
              
                def
              
              
                now
              
              
                (
              
              
                )
              
              
                :
              
              
                print
              
              
                (
              
              
                '2015-3-25'
              
              
                )
              
              

now
              
                (
              
              
                )
              
              
                #execute now():
              
              
                #2015-3-25
              
            
          

首先執行log(‘execute’),返回的是decorator函數,再調用返回的函數,參數是now函數,返回值最終是wrapper函數。

二、閉包

(1)概念:

在一個內部函數中,對外部作用域的變量進行引用,(并且一般外部函數的返回值為內部函數),那么內部函數就被認為是閉包。
維基百科上的解釋是:

              
                在計算機科學中,閉包(Closure)是詞法閉包(Lexical Closure)的簡稱,
是引用了自由變量的函數。這個被引用的自由變量將和這個函數一同存在,
即使已經離開了創造它的環境也不例外。
所以,有另一種說法認為閉包是由函數和與其相關的引用環境組合而成的實體。

              
            

在這里插入圖片描述

add訪問了外部函數start的變量,并且函數返回值為add函數(python可以 返回函數
python 裝飾函數 和 閉包 基礎總結。_第2張圖片
閉包,顧名思義,就是一個封閉的包裹,里面包裹著 自由變量 ,就像在類里面定義的屬性值一樣,自由變量的可見范圍隨同包裹,哪里可以訪問到這個包裹,哪里就可以訪問到這個自由變量。

再通過Python的語言介紹一下,一個閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫做閉包。你在調用函數A的時候傳遞的參數就是自由變量(當函數A的生命周期結束之后,自由變量依然存在,因為它被閉包引用了,所以不會被回收。)。

(2)常見問題

  1. 閉包無法修改 外部函數 局部變量 (即add函數無法修改start函數定義的變量)

  2. 閉包使得 局部變量 函數外 被訪問成為可能

  3. 閉包避免了使用全局變量

  4. 閉包允許將函數與其所操作的某些數據(環境)關連起來。

  5. 裝飾器就是一種的閉包的應用,只不過其傳遞的是 函數

  6. 閉包的最大特點是可以將 父函數的變量與內部函數綁定 ,并返回綁定變量后的函數(也即閉包)。(類似類)

  7. python循環中不包含域的概念。

python 裝飾函數 和 閉包 基礎總結。_第3張圖片
loop在python中是沒有域的概念的,flist在向列表中添加func的時候,并沒有保存i的值,而是當執行f(2)的時候才去取,這時候循環已經結束,i的值是2,所以結果都是4。

解決辦法:
在func外面再定義一個makefun函數,func形成閉包。 python 裝飾函數 和 閉包 基礎總結。_第4張圖片
參考:
https://foofish.net/python-closure.html
https://zhuanlan.zhihu.com/p/22229197


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

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

【本文對您有幫助就好】

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

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 镇远县| 尚义县| 靖边县| 个旧市| 大宁县| 富宁县| 莱芜市| 义马市| 五河县| 栾城县| 都江堰市| 志丹县| 永新县| 枣强县| 华阴市| 邮箱| 沙坪坝区| 英吉沙县| 南木林县| 乡宁县| 漠河县| 大英县| 承德市| 桦甸市| 渑池县| 汝城县| 华阴市| 化州市| 华宁县| 长治市| 阿拉善右旗| 江西省| 周宁县| 格尔木市| 康保县| 同心县| 正阳县| 呼和浩特市| 太湖县| 黄大仙区| 渭源县|