裝飾器

裝飾器

  • 最簡裝飾器緩存

      def deco(func):
          def wrap(*args, **kwargs):
              return func(*args, **kwargs)
          return wrap
      @deco
      def foo(a, b):
          return a ** b
     
  • 原理app

    • 對比被裝飾先後的 foo.__name__foo.__doc__函數

        from functools import wraps
        def deco(func):
            '''i am deco'''
            @wraps(func) # 還原被裝飾器修改的原函數屬性
            def wrap(*args, **kwargs):
                '''i am wrap'''
                return func(*args, **kwargs)
            return wrap
       
    • 簡單過程ui

        fn = deco(func)
        foo = fn
        foo(*args, **kwargs)
       
    • 多個裝飾器疊加調用的過程spa

        @deco1
        @deco2
        @deco3
        def foo(x, y):
            return x ** y
        # 過程拆解 1
        fn3 = deco3(foo)
        fn2 = deco2(fn3)
        fn1 = deco1(fn2)
        foo = fn1
        foo(3, 4)
        # 過程拆解 2
        # 單行: deco1( deco2( deco3(foo) ) )(3, 2)
        deco1(
            deco2(
                deco3(foo)
            )
        )(3, 4)
       
  • 帶參數的裝飾器日誌

      def deco(n):
          def wrap1(func):
              def wrap2(*args, **kwargs):
                  return func(*args, **kwargs)
              return wrap2
          return wrap1
      # 調用過程
      wrap1 = deco(n)
      wrap2 = wrap1(foo)
      foo = wrap2
      foo()
      # 單行形式
      check_result(30)(foo)(4, 8)
     
  • 裝飾器類和 __call__code

      class Deco:
          def __init__(self, func):
              self.func = func
          def __call__(self, *args, **kwargs):
              return self.func(*args, **kwargs)
      @Deco
      def foo(x, y):
          return x ** y
      # 過程拆解
      fn = Deco(foo)
      foo = fn
      foo(12, 34)
     
  • 使用場景string

    • 參數、結果檢查it

    • 緩存、計數io

    • 日誌、統計

    • 權限管理

    • 重試

    • 其餘

  • 練習1: 寫一個 timer 裝飾器, 計算出被裝飾函數調用一次花多長時間, 並把時間打印出來

      import time
      from functools import wraps
      def timer(func):
          @wraps(func) # 修正 docstring
          def wrap(*args, **kwargs):
              time0 = time.time()
              result = func(*args, **kwargs)
              time1 = time.time()
              print(time1 - time0)
              return result
          return wrap
     
  • 練習2: 寫一個 Retry 裝飾器

      import time
      class retry(object):
          def __init__(self, max_retries=3, wait=0, exceptions=(Exception,)):
              self.max_retries = max_retries
              self.exceptions = exceptions
              self.wait = wait
          def __call__(self, func):
              def wrapper(*args, **kwargs):
                  for i in range(self.max_retries + 1):
                      try:
                          result = func(*args, **kwargs)
                      except self.exceptions:
                          time.sleep(self.wait)
                          continue
                      else:
                          return result
              return wrapper
相關文章
相關標籤/搜索