Python 0502-アクセサリー

24794 ワード

  • デコレーションデマンド
  • 需要の改善、業務機能の分離
  • 需要を改善し、
  • を参照
  • 需要を改善し、コリー化
  • 装飾器文法糖
  • デコレーション説明
  • コードデモ
  • どのように装飾器を理解しますか?
  • 文書文字列
  • 装飾器副作用
  • パッケージ関数属性
  • 包装関数属性説明
  • 包装関数コリー化
  • アクセサリ付き
  • アクセサリ付きまとめ
  • アクセサリ付きフレキシブル制御
  • functoolsモジュール
  • コードデモ
  • functoolsモジュール@
  • コード最適化


  • 装飾品の要件
  • 加算関数は、その機能を強化するために、呼び出すパラメータ情報
  • を出力することができる.
    def add(x,y):
        return x+y
    #          
    def add(x, y):
        print("calladd, x+y")  #       
        return x+y
  • 上の加算関数は需要を達成したが以下の欠点がある.
  • 印刷文の結合が高すぎる
  • 加算関数は業務機能に属するが、情報を出力する機能は、非業務機能コードに属し、業務関数加算に
  • を置くべきではない.

    ニーズの改善、ビジネス機能の分離
  • は業務機能の分離を実現したが、fn関数呼び出しパラメータは問題
  • である.
    def add(x, y):
        return x + y
    
    def logger(fn):
        print('begin')  #      
        x = fn(4, 5)
        print('end')  #      
        return x
    
    print(logger(add))
    ----------------------------
    begin
    end
    9

    ニーズの改善、導入
  • は伝参の問題を解決し、
  • をさらに変更した.
    def add(x, y):
        return x + y
    
    def logger(fn, *args, **kwargs):
        print('begin')
        x = fn(*args, **kwargs)
        print('end')
        return x
    
    print(logger(add, 4, y=5))
    --------------------------------
    begin
    end
    9

    需要を改善し、コリー化
    def add(x, y):
        return x + y
    
    def logger(fn):
        def _logger(*args, **kwargs):
            print('begin')
            x = fn(*args, **kwargs)
            print('end')
            return x
        return _logger
    
    print(logger(add)(5, y=50))
    #        
    add = logger(add)  #     _logger,   =  ,add1       ,fn       
    print(add(x=5, y=10))  # logger(add, x=5, y=10)

    装飾器文法糖
    def logger(fn):
        def wrapper(*args, **kwargs):
            print('begin')
            x = fn(*args, **kwargs)
            print('end')
            return x
        return wrapper
    
    @logger  #     add = logger(add)
    def add(x, y):
        return x + y
    
    print(add(45, 40))
  • @loggerとは何ですか?これが装飾文法
  • です.
    アクセサリーの説明
  • デコレーション(無参)
  • 関数
  • です
  • 関数をそのパラメータとして
  • 戻り値も関数
  • である.
  • @functionname方式を使用して、呼び出し
  • を簡略化することができる.
  • 装飾器と高次関数
  • デコレーションは高次関数であるが、デコレーションは伝達関数の機能に対するデコレーション(機能強化)
  • である.

    コードデモ
    import datetime
    import time
    
    def logger(fn):
        def wrap(*args, **kwargs):
            # before     
            print("args={}, kwargs={}".format(args,kwargs))
            start = datetime.datetime.now()
            ret = fn(*args, **kwargs)
            # after     
            duration = datetime.datetime.now() - start
            print("function{} took {}s."
                  .format(fn.__name__, duration.total_seconds()))
            return ret
        return wrap
    
    
    @logger #     add = logger(add)
    def add(x, y):
        print("===call add===========")
        time.sleep(2)
        return x + y
    
    
    print(add(4, y=7))
    ---------------------------------
    args=(4,), kwargs={'y': 7}
    ===call add===========
    function add took 2.016632s.       #   :        add
    11

    どのように装飾器を理解しますか?
    に縁を付ける
    装飾関数
    ガラス
    プリアンブル機能の強化
    絵をかく
    エンハンス関数
    これがコア
    バックプレート
    バックグラウンド機能の強化
    ドキュメント文字列
  • Pythonのドキュメント
  • Pythonは、文書文字列Documentation Strings
  • です.
  • は、関数文ブロックの最初の行であり、複数行のテキストに慣れているため、三引用符
  • を多く使用する.
  • 慣例は頭文字の大文字で、第1行は概要を書いて、空の1行、第3行は詳しく
  • を書きます
  • この文書
  • には、特殊な属性docを使用してアクセスできます.
    def add(x, y):
        """This is a function of addition"""
        a = x + y
        return x + y
    
    
    print("name={}
    doc={}"
    .format(add.__name__, add.__doc__)) print("====================") print(help(add)) --------------------------------------------------------- name=add doc=This is a function of addition ==================== Help on function add in module __main__: add(x, y) This is a function of addition None

    アクセサリー副作用
    def logger(fn):
        def wrapper(*args, **kwargs):
            """I am wrapper"""
            print("begin")
            x = fn(*args, **kwargs)
            print("end")
            return x
        return wrapper
    
    
    @logger  # add = logger(add)
    def add(x, y):
        """This is a function for add"""
        return x + y
    
    
    print("name={}
    doc={}"
    .format(add.__name__, add.__doc__)) ------------------------------------------- name=wrapper doc=I am wrapper
  • 元の関数オブジェクトの属性はすべて置き換えられましたが、装飾器を使用して、カプセル化された関数の属性を表示する必要があります.どのように解決しますか?

  • パッケージ関数のプロパティ
  • は、カプセル化された関数属性==copy==>パッケージ関数属性
  • を提供する.
    def copy_properties(src, dst):
        #         ==copy==>       (                   )
        dst.__name__ = src.__name__
        dst.__doc__ = src.__doc__
    
    
    def logger(fn):
        def wrapper(*args, **kwargs):
            """I am wrapper"""
            print("begin")
            x = fn(*args, **kwargs)
            print("end")
            return x
        copy_properties(fn, wrapper)  # fn    src,wrapper    dst
        return wrapper
    
    @logger
    def add(x, y):
        """This is a function for add"""
        return x + y
    
    
    print("name={}
    doc={}"
    .format(add.__name__, add.__doc__)) ------------------------------------- name=add doc=This is a function for add

    パッケージ関数のプロパティの説明
  • copy_を通過properties関数は、包装関数の属性によって包装関数
  • を上書きする
  • 装飾された関数はすべてこれらの属性を複製する必要があり、この関数は
  • に共通している.
  • は、複製属性の関数を装飾器関数として構築することができ、装飾器
  • を有する.
    ほうそうかんすうコリーか
  • は、パッケージされた関数属性=copy==>パッケージ関数属性を提供し、アクセサリ付き
  • に改造する.
    def copy_properties(src):  #    
        def _copy(dst):
            #         ==copy==>       
            dst.__name__ = src.__name__
            dst.__doc__ = src.__doc__
            return dst
        return _copy
    
    
    def logger(fn):
        @copy_properties(fn)  # wrapper = copy_properties(fn, wrapper)
        def wrapper(*args, **kwargs):
            """I am wrapper"""
            print("begin")
            x = fn(*args, **kwargs)
            print("end")
            return x
        return wrapper
    
    @logger  # add = logger(add)
    def add(x, y):
        """This is a function for add"""
        return x + y
    
    
    print("name={}
    doc={}"
    .format(add.__name__, add.__doc__)) --------------------------------------------- name=add doc=This is a function for add

    パラメトリック装飾
  • 需要:関数の実行時間を取得し、時間がしきい値を超える関数に対して
  • を記録する.
    import datetime
    import time
    
    def copy_properties(src):  #    
        def _copy(dst):
            #         ==copy==>       
            dst.__name__ = src.__name__
            dst.__doc__ = src.__doc__
            return dst
        return _copy
    
    
    def logger(duration):
        def _logger(fn):
            @copy_properties(fn)  # wrapper = copy_properties(fn, wrapper)
            def wrapper(*args, **kwargs):
                """I am wrapper"""
                start = datetime.datetime.now()
                x = fn(*args, **kwargs)
                delta = (datetime.datetime.now()-start).total_seconds()
                print('so slow') if delta > duration else print('so fast')
                return x
            return wrapper
        return _logger
    
    
    @logger(5)  # add = logger(5)(add)
    def add(x, y):
        """This is a function for add"""
        time.sleep(3)
        return x + y
    
    
    print(add(5, 6))
    -----------------------------------------
    so fast
    11

    アクセサリー付きまとめ
  • 関数
  • です
  • 関数をそのパラメータとして
  • 戻り値は、パラメータを持たない装飾関数
  • である.
  • @functionname(パラメータリスト)方式で
  • を呼び出す
  • は、装飾器の外層に関数
  • を追加したものと見なすことができる.
    アクセサリ付きフレキシブル制御
  • は、記録する機能を抽出し、外部から供給する関数により出力
  • を柔軟に制御することができる.
    import datetime
    import time
    
    def copy_properties(src):  #    
        def _copy(dst):
            #         ==copy==>       
            dst.__name__ = src.__name__
            dst.__doc__ = src.__doc__
            return dst
        return _copy
    
    
    def logger(duration,
               func=lambda name,
                duration:print("{} took {}s".format(name, duration))):
        def _logger(fn):
            @copy_properties(fn)  # wrapper = copy_properties(fn, wrapper)
            def wrapper(*args, **kwargs):
                """I am wrapper"""
                start = datetime.datetime.now()
                x = fn(*args, **kwargs)
                delta = (datetime.datetime.now()-start).total_seconds()
                if delta > duration:
                    func(fn.__name__, duration)
                return x
            return wrapper
        return _logger
    
    
    @logger(2)  # add = logger(2)(add)
    def add(x, y):
        """This is a function for add"""
        time.sleep(3)
        return x + y
    
    
    print(add(5, 6))
    --------------------------------------
    add took 2s
    11

    functoolsモジュール
  • functools.update_wrapper(wrapper, wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
  • 類似copy_properties機能
  • wrapperパッケージ関数、更新者、wrappedパッケージ関数、データソース
  • ユニットWRAPPER_ASSIGNMENTSでは上書きする属性‘module’,‘name’,‘qualname’,‘doc’,‘annotations’モジュール名,名称,限定名,ドキュメント,パラメータ注記
  • ユニットWRAPPER_UPDATESでは更新される属性であり、dict属性辞書
  • wrappedプロパティを追加し、wrapped関数
  • を保持します.

    コードデモ
    import datetime, time, functools
    
    
    def logger(duration,
               func=lambda name,
                duration:print("{} took {}s".format(name, duration))):
        def _logger(fn):
            def wrapper(*args, **kwargs):
                """I am wrapper"""
                start = datetime.datetime.now()
                x = fn(*args, **kwargs)
                delta = (datetime.datetime.now()-start).total_seconds()
                if delta > duration:
                    func(fn.__name__, duration)
                return x
            return functools.update_wrapper(wrapper, fn)
            #      (wrapper, fn),functools.update_wrapper(wrapper, wrapped)wrapper     、    ,wrapped      、   
        return _logger
    
    
    @logger(2)  # add = logger(2)(add) # logger(2) => _logger add=_logger(add)
    def add(x, y):
        """This is a function for add"""
        time.sleep(1)
        return x + y
    
    
    print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='
    '
    ) ------------------------------------- 11 add 0x0000024974109158> {'__wrapped__': 0x0000024974109158>}

    functoolsモジュール@
  • @functools.wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES)
  • 類似copy_properties機能
  • wrapped被包装関数
  • ユニットWRAPPER_ASSIGNMENTSでは上書きする属性‘module’,‘name’,‘qualname’,‘doc’,‘annotations’モジュール名,名称,限定名,ドキュメント,パラメータ注記
  • ユニットWRAPPER_UPDATESでは更新される属性であり、dict属性辞書
  • wrappedプロパティを追加し、wrapped関数
  • を保持します.

    コード最適化
    import datetime, time, functools
    
    
    def logger(duration,
               func=lambda name,
                duration:print("{} took {}s".format(name, duration))):
        def _logger(fn):
            @functools.wraps(fn)  # wrapper = functools.wraps(fn, wrapper)
            #    fn?@functools.wraps(wrapped), wrapped       
            def wrapper(*args, **kwargs):
                """I am wrapper"""
                start = datetime.datetime.now()
                x = fn(*args, **kwargs)
                delta = (datetime.datetime.now()-start).total_seconds()
                if delta > duration:
                    func(fn.__name__, duration)
                return x
            return wrapper
        return _logger
    
    
    @logger(2)  # add = logger(2)(add)
    def add(x, y):
        """This is a function for add"""
        time.sleep(1)
        return x + y
    
    
    print(add(5, 6), add.__name__, add.__wrapped__, add.__dict__, sep='
    '
    ) --------------------------------- 11 add 0x000001F674779158> {'__wrapped__': 0x000001F674779158>}