1. 程式人生 > >python裝飾器裝飾原理探秘

python裝飾器裝飾原理探秘

urn fun python裝飾器 草稿 app pri 返回 註意 個人理解

最近一直沒抽出時間來寫博客,這篇博客在草稿箱裏面躺了好久了,一直都只有一個標題。
現在終於要開始寫了。

  1. 為什麽要寫這個篇文章

    前段時間整天盯著python學習 群,發現好多同學對python很多內容並不是很理解,覺得有必要分享自己這段時間通過學習實踐總結出來的一些東西。
    寫的過程中我會將一些自己理解的內容直接用文字寫出來,感覺沒必要去復制粘貼一些概念性的東西,若存在有理解錯誤的地方,歡迎各位在留言指出一起討論提高,SO 廢話不說開寫吧。

  2. 什麽是裝飾器

    裝飾器(Decorator):個人理解裝飾器無非就是一個函數,函數的功能是傳入一個源函數,丟回來一個包含原函數功能的閉包來替代原函數以供調用。
    哎呀 又扯出一個閉包概念⊙﹏⊙b汗 關於閉包下次有空再寫一篇

  3. 裝飾器的分類

    以實現一個非常無聊的功能(控制函數運行次數)的裝飾器進行舉例

    • 不帶參數的裝飾器

      不帶參數的裝飾器是真正裝的飾器,通過傳入一個函數返回一個閉包代替原函數,不帶參數的裝飾器定義方式如下:

      def my_decorator(func):
          li = list()
          limit = 5
      
          def inner(*args, **kwargs):
              # do some thing
              li.append(1)
              if len(li) > limit:
                  print(‘<%s>只能被調用%s次‘ % (func.__name__, limit))
                  return
              else:
                  return func(*args, **kwargs)
      
          return inner
      
      
      @my_decorator
      def my_func1(n):
          print(‘n is %s‘ % n)
      
      
      def my_func2(n):
          print(‘func2 n is %s‘ % n)
      
      
      for i in range(10):
          my_func1(i)
          my_func2(i)

      執行結果

      n is 0
      func2 n is 0
      n is 1
      func2 n is 1
      n is 2
      func2 n is 2
      n is 3
      func2 n is 3
      n is 4
      func2 n is 4
      <my_func1>只能被調用5次
      func2 n is 5
      <my_func1>只能被調用5次
      func2 n is 6
      <my_func1>只能被調用5次
      func2 n is 7
      <my_func1>只能被調用5次
      func2 n is 8
      <my_func1>只能被調用5次
      func2 n is 9

      通過返回一個inner閉包 實現限制執行次數

    • 帶參數的裝飾器

      帶參數的裝飾器函數本身嚴格意義上並不能算是裝飾器,實際上帶參數的裝飾器函數是一個返回值為裝飾器函數的一個函數。
      為什麽要有帶參數的裝飾器?
      就拿前面舉的例子來說: 雖然my_decorator實現的功能比較無聊,但是我還是感覺這個無聊的功能不夠完美,因為函數執行次數限制在裝飾器裏面寫死了,假如我要限制好幾個不同的函數,每個函數限制不同執行次數,那麽按照不帶參數的裝飾器的寫法每個限制的執行次數我都要重新寫一個裝飾器,這顯然非常不合理。於是我需要一個帶參數的裝飾器來實現這種功能。
      下面是實現該功能的函數寫法:

      def my_decorator(limit):
      
          def outer(func):
              li = list()
      
              def inner(*args, **kwargs):
                  # do some thing
                  li.append(1)
                  if len(li) > limit:
                      print(‘<%s>只能被調用%s次‘ % (func.__name__, limit))
                      return
                  else:
                      return func(*args, **kwargs)
      
              return inner
          return outer
      
      
      @my_decorator(2)
      def my_func1(n):
          print(‘n is %s‘ % n)
      
      
      @my_decorator(4)
      def my_func2(n):
          print(‘func2 n is %s‘ % n)
      
      
      for i in range(5):
          my_func1(i)
          my_func2(i)

      眼尖的同學可能註意到了這裏裝飾器裝飾寫法和不帶參數的不同,不帶參數時@後面直接接的裝飾器函數名,此處@後面接了裝飾器函數名後還有一對括號和參數。
      帶了括號和參數意味著函數已經被執行了,相當於@後面跟著的是函數執行的返回值,所以my_decorator函數返回的outer函數閉包才是真正意義上的裝飾器函數,
      通過my_decorator的參數limit 我們就可以每次裝飾一個函數時都可以指定不同的函數執行次數上限。
      執行結果

      n is 0
      func2 n is 0
      n is 1
      func2 n is 1
      <my_func1>只能被調用2次
      func2 n is 2
      <my_func1>只能被調用2次
      func2 n is 3
      <my_func1>只能被調用2次
      <my_func2>只能被調用4次
  4. 關於“@”符號

    • @符號作用

      @符號是python中的一個語法糖 為了讓裝飾語句寫起來更加簡單代碼更加易讀。
      在函數定義前一行放置@符號後面接一個裝飾器函數名代表該函數被裝飾器裝飾,相當於在函數定義之後立馬執行了一條語句:
      func=decorator(func)
      此處func為被裝飾函數,decorator為裝飾器函數。
    • @ 符號給初學者帶來的障礙

      @符號各種方便但是給初學者理解裝飾器帶來了一定障礙:初學者很容易忘掉@的實際作用,然後就會想不通裝飾器到底是怎麽裝飾的。
      So 其實這個障礙是我寫這篇文章的主要原因。

  5. 裝飾器的裝飾過程

    終於寫到了正題 ,正題還是以限制

python裝飾器裝飾原理探秘