pythonアクセサリーの詳細

6325 ワード

前言
この文章はpython 3の中の装飾器についてのいくつかの認識を書いて、知識のレベルを高めるつもりです.
1アクセサリーは何ですか
装飾器は本質的にPython関数/クラスであり、他の関数/クラスがコード修正を必要とせずに追加機能を追加することができ、装飾器の戻り値も関数/クラスオブジェクトである.ログの挿入、パフォーマンステスト、パーミッションチェックなどのシーンでは、このような問題を解決するために、装飾器が優れた設計であるなど、断面的なニーズのあるシーンでよく使用されます.装飾器があれば,関数機能自体に関係のないコードを装飾器に多重化することができる.要約すると、装飾器の役割は、既存のオブジェクトに追加の機能を追加することです.
2シンプルなデコレーション(@記号は使用しない)
簡単なアクセサリーの例ですlog_appendはdirectを飾るprint,この書き方は任意のパラメータのdirect_をサポートするprintは、任意のパラメータの装飾関数log_もサポートします.append
def log_append():
    def decorator(func):
        def wrapper(**kwargs):
            if "name" in kwargs:
                print("check name %s" % (kwargs.get("name")))
            else:
                print("check name fail" )
                return
            return func(**kwargs)
        return wrapper
    return decorator

def direct_print(**kwargs):
    print("print name is %s"% (kwargs.get("name")))

    
fun_decoratored=log_append()(direct_print)
fun_decoratored(names="111")

fun_decoratored(name="111")

print(fun_decoratored)

direct_print(name="111")

3用@記号
@記号を利用して、コードの読解性を高めることができて、私達は@の方式で上のコードを書き換えます
def log_append():
    def decorator(func):
        def wrapper(**kwargs):
            if "name" in kwargs:
                print("check name %s" % (kwargs.get("name")))
            else:
                print("check name fail" )
                return
            return func(**kwargs)
        return wrapper
    return decorator
@log_append()
def direct_print(**kwargs):
    print("print name is %s"% (kwargs.get("name")))

    


direct_print(name="111")

direct_print(names="111")


4装飾器関数パラメータを伝達し、装飾器の利便性を体現する
インタフェース強制チェックのルールが不定の場合、1つの関数はnameを強制チェックし、もう1つの強制チェックnamesフィールドは、後でキーなどの他のフィールドを強制チェックし、log_を書き換える可能性があります.appendは便利です次のコードはまったく変更されませんdirect_printビジネスロジックの場合、検証ロジックが書き換えられdirect_に多重化されるprint_namesメソッド
from collections import Iterable


def log_append(au_keys=[]):
    def decorator(func):
        def wrapper(**kwargs):
            if not isinstance(au_keys,Iterable):
                raise Exception("error au_keys,should be Iterable str")
            for check_key in au_keys:
                if check_key in kwargs:
                    print("check %s %s" % (check_key,kwargs.get(check_key)))
                else:
                    print("check %s fail
"% (check_key)) return return func(**kwargs) return wrapper return decorator @log_append(["name"]) def direct_print(**kwargs): print("print name is %s
"% (kwargs.get("name"))) @log_append(["names"]) def direct_print_names(**kwargs): print("print names is %s
"% (kwargs.get("names"))) direct_print(name="111") direct_print(names="111") direct_print_names(name="111") direct_print_names(names="111")

5 functools.wraps保持関数情報
functoolsは使用しません.wrapsはdirect_を使用するなどdocstring、nameなどの関数メタ情報を失う可能性があります.print_names.nameはwrapperを返します.これは使用に影響します.だからfunctoolsが必要です.wraps.加入方式は簡単で、再装飾関数がfuncに伝わるところに@wrapsを加える
from collections import Iterable
from functools import wraps


def log_append(au_keys=[]):
    def decorator(func):
        @wraps(func)
        def wrapper(**kwargs):
            print()
            if not isinstance(au_keys,Iterable):
                raise Exception("error au_keys,should be Iterable str")
            for check_key in au_keys:
                if check_key in kwargs:
                    print("check %s %s" % (check_key,kwargs.get(check_key)))
                else:
                    print("check %s fail
"% (check_key)) return return func(**kwargs) return wrapper return decorator @log_append(["name"]) def direct_print(**kwargs): print("print name is %s
"% (kwargs.get("name"))) @log_append(["names"]) def direct_print_names(**kwargs): print("print names is %s
"% (kwargs.get("names"))) direct_print(name="111") direct_print(names="111") direct_print_names(name="111") direct_print_names(names="111") print(direct_print.__name__)

6呼び出し順序
pythonは多重装飾をサポートしており、使用方法は1つ1つ@で書かれており、その実行順序は外から中へ、最初に最外層の装飾器を呼び出し、最後に最下層の装飾器を呼び出して上のコードに印刷時間の装飾関数print_を加えるtime、direct_print先装print_time,direct_print_names後飾り、実はdirect_print効果は等しい
 print_time(log_append(["name"])(direct_print))

direct_print_names効果は等しい
 log_append(["_names"])(print_time(direct_print))

全体コードは以下の通りです.
from collections import Iterable
from functools import wraps

import time


def log_append(au_keys=[]):
    def decorator(func):
        @wraps(func)
        def wrapper(**kwargs):
            print()
            if not isinstance(au_keys,Iterable):
                raise Exception("error au_keys,should be Iterable str")
            for check_key in au_keys:
                if check_key in kwargs:
                    print("check %s %s" % (check_key,kwargs.get(check_key)))
                else:
                    print("check %s fail
"% (check_key)) return return func(**kwargs) return wrapper return decorator def print_time(func): @wraps(func) def wrapper(**kwargs): print("time is %s"%(time.strftime("%Y-%m-%d %H:%M;%S",time.localtime()))) return func(**kwargs) return wrapper @print_time @log_append(["name"]) def direct_print(**kwargs): print("print name is %s
"% (kwargs.get("name"))) @log_append(["names"]) @print_time def direct_print_names(**kwargs): print("print names is %s
"% (kwargs.get("names"))) direct_print(name="111") direct_print(names="111") direct_print_names(name="111") direct_print_names(names="111") print(direct_print.__name__)

締めくくり
この文章を見て、pythonの装飾器はほとんど悪くないでしょう、よく勉強して、毎日向上します^^;