Pythonアクセサリー学習ノート


以前は<を見てdecoratorに出会ったときに霧の中で見ていましたが、それから多管にも行かず、後でこの問題に遭遇したときに解決しようと思っていました.今日Djangoコードを見てlogin_を見ましたrequiredなどの装飾器でまたこれに出会ったので、ネット上でいくつかのドキュメントを探して再学習し、ここでまとめました.
1.アクセサリーの意味
装飾器は有名な設計モデルで、断面的なニーズのあるシーンによく使われ、挿入ログ、パフォーマンステスト、トランザクションなどが古典的です.装飾器はこのような問題を解決する絶好の設計であり、装飾器があれば、多くの関数の中で関数機能自体に関係のない同じコードを抽出し、再利用を続けることができます.要約すると、装飾器の役割は、既存のオブジェクトに追加の機能を追加することです.
2.装飾文法
(1)無パラメータ装飾器
def deco(func):
    print("deco")
    return func

@deco
def foo():
    print("foo")

foo()

最初の関数decoは装飾関数であり、そのパラメータは装飾された関数オブジェクトである.伝達された関数オブジェクトをdeco関数内で「装飾」し、このオブジェクトに戻ることができます(
必ず戻ることを覚えて
ああ、そうでなければ、外でfooを呼び出す場所には関数がありません.実はこのときfoo=deco(foo)
(2)パラメータ付装飾器
被装飾関数パラメータなし
def deco(argv):
    def decorator(func):
        print("decorator")
        return func
    print("deco")
    print(argv)
    return decorator

@deco("123")
def foo():
    print("foo")

foo()

最初の関数decoは装飾関数であり、そのパラメータは「装飾を強化する」ために使用されます.この関数は装飾された関数オブジェクトではないため、内部に少なくとも装飾された関数を受け入れる関数を作成し、このオブジェクトに戻る必要があります.実際このときfoo=deco(argv)(foo)
被装飾関数にもパラメータがあります
from functools import wraps

def deco(argv):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print("wrapper")
            return func(*args, **kwargs)
        print("decorator")
        return wrapper
    print("deco")
    print(argv)
    return decorator

@deco("123")
def foo(data):
    "this is foo"
    print("foo")
    print(data)

foo("afdasdf")

print(foo.__name__, foo.__doc__)
decorator関数の内部には、被装飾関数のパラメータを受け入れるための関数を定義する必要がある.このときfoo=deco(argv)(foo)(data)
まず5行目に注意し、この行を注釈するとfoo._name__これは「wrapper」で、この装飾器を使って装飾した後のfoo._name__元のfooか、wraps装飾器はfuncの一般的な属性をwrapper関数に与えた.また、この装飾器にはパラメータが付いていることにも気づいたと思います.実際には、assignedのプロパティ名は割り当てられた方法で置き換えられ、updatedのプロパティ名はupdateでマージされ、functoolsのソースコードを表示することでデフォルト値を得ることができます.この装飾器についてはwrapper=functoolsに相当する.wraps(func)(wrapper)
(3)マルチアクセサリーの組み合わせ使用
def deco_1(func):
    def __deco_1(*args, **kwargs):
        print("__deco_1")
        return func(*args, **kwargs)
    print("deco_1")
    return __deco_1

def deco_2(func):
    def __deco_2(*args, **kwargs):
        print("__deco_2")
        return func(*args, **kwargs)
    print("deco_2")
    return __deco_2

@deco_2
@deco_1
def test():
    print("test")

# test = deco_1(test)
# print(test)
# test = deco_2(test)
# print(test)

test()

出力内容は次のとおりです.
deco_1 deco_2 __deco_2 __deco_1 test
関数testを宣言すると前の2行が出力され、実際に実行すると後の3行が出力されます.2つの装飾器は、注釈部分と同様に置き換えることができます.
(4)例
def makebold(func):
    def wrapped():
        return "<b>" + func() + "</b>"
    return wrapped

def makeitalic(func):
    def wrapped():
        return "<i>" + func() + "</i>"
    return wrapped

@makebold
@makeitalic
def say():
    return "Hello"

print(say())

#output
'''
<b><i>Hello</i></b>
'''

3.体得
複数の関数に重複コードがある場合、この部分のコードを個別に取り出して1つの装飾器に整理し、各関数に対して装飾器を呼び出すことで、コードの多重化を実現し、元の関数をより軽くすることができます.
また、パラメータの正当性をチェックするなど、複数の作成済み関数に共通の機能を追加する必要があります.パラメータの正当性を確認する必要がある関数ごとに呼び出しを出すと、各関数の内部修正を行わずに、正当性を確認する装飾器を単独で書くことができます.
参照先:
1.Pythonアクセサリー学習
2.Python装飾器とフェース向けプログラミング