Python階段の装飾器

4780 ワード

1.最も基本的な装飾器
  • 装飾器の基本的なやり方:関数が進み、関数が出る.関数名はパラメータとして装飾器に入力、関数は:装飾器は関数を返す.

  • 装飾器は断面プログラミングに対する思想(AOP)を体現し、中間部品と同じである.
    from functools import wraps
    
    def deco(func):
        #     ,       func   .
        @wraps(func)
        def inner(*args, **kwargs):
            """
            this is a inner function
            """
            #   func
            print('decorating...')
            result = func(*args, **kwargs)
            return result
        return inner
    
    
    # @  python                .
    @deco
    def foo(x, y):
        """
        return x ** y
        """
        return x ** y
    
    
    foo(2, 10)
    
    # @          ,     func  deco,       foo = deco(func)
    #    foo   deco   
    foo_ = deco(foo)(2, 10)
    
    
    #                ,       __doc__,     __name__
    #    functools     wraps           docstring name
    print(foo.__name__)  # foo
    print(foo.__doc__)  # '
    return x ** y
    '
  • パラメータ付き装飾器
  • パラメータ付きの装飾器は、最も簡単な装飾器にもう一つの関数を組み合わせて、追加のパラメータを受信する.
    from functools import wraps
    
    def limit_output(max_value):
        def deco(func):
            #     ,       func   .
            @wraps(func)
            def inner(*args, **kwargs):
                """
                this is a inner function
                """
                #   func
                print('decorating...')
                result = func(*args, **kwargs)
                if result > max_value:
                    return '   ,     '
                return result
            return inner
        return deco
    
    @limit_output(10000000000000000000000)
    def foo(x,y):
        """
        return x ** y
        """
        return x ** y
    
    foo(20,10)
    out:decorating...
      10240000000000
    
    foo(20, 10000)
    out:decorating...
      '   ,     '
    

    2.アクセサリー
    クラス装飾器を実現するには、クラスに__call__の方法を実現させなければならない.
    class Deco:
        def __init__(self, func):
            self.func = func
            
        def __call__(self, *args, **kwargs):
            #   func
            result = self.func(*args, **kwargs)
            print('Class Deco...')
            return result  
    
    #     
    @Deco
    def foo(x,y):
        return x ** y
    
    foo(2,3)
    out:Class Deco...
        8
    
  • パラメータ付きクラス装飾器
  • パラメータ付きクラス装飾器は、パラメータをinitから伝達するものであり、関数はcallから伝達され、call方法には内部関数が必要である.
    class Deco:
        def __init__(self, max_value):
            self.max_value = max_value
            
        def __call__(self, func):
            def inner(*args, **kwargs):
                result = func(*args, **kwargs)
                if result > self.max_value:
                    return '     .'
                else:
                    return result
            return inner
    
    #         
    @Deco(10000000000000)
    def foo(x,y):
        return x ** y
    
    foo(2,3)
    out:8
    
    foo(2,2000)
    out:'     .'
    

    3.多層装飾器
    多層装飾器は中から外へ実行する.
    def deco1(func):
        print('enter deco1...')
        def  inner1(*args, **kwargs):
            print('enter inner1...')
            return func(*args, **kwargs)
        print('exiting deco1...')
        return inner1
    
    def deco2(func):
        print('enter deco2...')
        def  inner2(*args, **kwargs):
            print('enter inner2...')
            return func(*args, **kwargs)
        print('exiting deco2...')
        return inner2
    
    
    def deco3(func):
        print('enter deco3...')
        def  inner3(*args, **kwargs):
            print('enter inner3...')
            return func(*args, **kwargs)
        print('exiting deco3...')
        return inner3
    
    #      
    @deco1
    @deco2
    @deco3
    def foo(x,y):
        return x ** y
    
    foo(2,3)
    enter deco3...
    exiting deco3...
    enter deco2...
    exiting deco2...
    enter deco1...
    exiting deco1...
    8
    

    4.練習問題
  • 練習1:timer装飾器を書いて、装飾関数に呼び出されるのにどれくらいの時間がかかるかを計算して、時間を
  • に印刷します.
    import time
    from funfunctools import wraps
    
    def timer(func):
        @wraps(func)  #    docstring
        def wrap(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(start - end)
            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