Python の @decorators について話す - 例を使用して (クラス デコレーターと関数デコレーターを含む)

Python の @decorator についての話

@ の使用に関しては、まずデコレータの概念について話さなければなりません

デコレータについて

公式ドキュメントの内容を見てみましょう。

デコレータは、ソフトウェア デザイン パターンに使用される名前です。デコレータは、サブクラスを直接使用したり、デコレートされる関数のソース コードを変更したりすることなく
、関数、メソッド、またはクラスの機能を動的に変更します。
パターンの名前。デコレータ直接サブクラス化したり、修飾される関数のソース コードを変更したりすることなく、関数、メソッド、またはクラスの機能を動的に変更できます。」 (Google 翻訳より)

Python におけるデコレータは、関数やメソッドの変更を容易にする Python 構文への特定の変更です。平たく言えば、デコレータは元の関数を変更せずに他の関数を追加することと同じです。たとえば、関数を使用するたびにマークとしてログを出力したいが、関数を直接変更したくない場合は、デコレーターが便利です。デコレーションとはその名の通り、ケーキに飾りを付けるという意味ですが、この例では「花」が丸太になっているのでしょう。

def triple_sum(a,b,c):
    print( "the sum is ",(a+b+c))
    
#log修饰器
def log_dec(func):
    def inner(a,b,c):
        print("logloglog")
        return func(a,b,c)
    return inner

new_fun=log_dec(triple_sum)
new_fun(1,2,3)

として出力
出力

ここには暗黙の事前知識ポイントもあります Python では、関数を変数として渡すことができます。

def triple_sum(a, b, c):
    print( "the sum is ",(a+b+c))

new_func = triple_sum
new_func(123, 234, 345)
print(new_func.__name__)

ここに画像の説明を挿入

関数に加えて、クラスもデコレータとしてラップできます。

class Cube(object):
    def __init__(self, args):
        self.args = args

    def __call__(self, x, y):
        res = self.args(x, y)
        return res * res * res
# 这里Cube作为一个三次方的包装器,包装了一个普通的乘法函数
# 这里的乘法函数我用一个lambda表达式来略缩了
mul_nums = Cube(lambda x, y: x * y)
# 不使用lambda函数的话就是
#def mul_nums(x, y):
#    return x * y
#mul_nums = Cube(mul_nums)

print(mul_nums)
print(mul_nums(4, 3))

小さな要約

つまり、デコレータとは実際には現在のモジュールに追加された新しい関数にすぎません。デコレータはクラスまたは関数にすることができます。設計手法の開閉原理に準拠した本来の機能自体は変わりません。

@(糖衣構文)について

@ は実際には Python の糖衣構文であり、@ を使用して上記の 2 つの例を変換します。
例 1:

def log_dec(func):
    print("logloglog")
    func(1,2,3)

@log_dec
def triple_sum(a,b,c):
    print( "the sum is ",(a+b+c))

結果の出力は次のようになります:
ここに画像の説明を挿入
Formula @ this 構文糖衣は

@Decorator 名はデコレータ名を置き換えます (装飾された関数)

つまり、triple_sum = log_dec(triple_sum)

例 2

@Cube
def mul_nums(x, y):
    return x * y

同様に、@Cube は mul_nums = Cube(mul_nums) を置き換えます。

高度

デコレータの順序

既存の関数に追加する関数は、@ (コード ブロックの順序) よりも前に宣言する必要があることに注意してください。同時に、関数は複数のデコレータを同時に追加できます。

一番下の @ 関数から実行が開始され、その下の関数が入力として使用されます。印刷するとより鮮明に見えます

def log1(func):
    print("log1log1log1")

def log2(func):
    print("log2log2log2")
    func(1, 2, 3)

@log1
@log2
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

出力は次のとおりです。実際の実行は、triple_sum = log2(triple_sum) Triple_sum = log1(triple_sum)
ここに画像の説明を挿入
と同等です。

デコレータとパラメータ

1.パラメータを渡す

おそらくこれを見て Huadian を発見した盲目の学生もいるでしょう。 Triple_sum にパラメータを渡す方法! (上記の例の値はすべてハードコーディングされています) ここでデコレーターを変更します。

変換の前に、Python では関数をネストすることができます。

def func1():
    print("I'm in func1")
    def func2(msg):
        print("I'm in func2")
        print("I'm saying ",msg)
    func2("hello")

func1()

ここに画像の説明を挿入
関数のネストをクリアした後、デコレーターのパラメーターを変更する方法を見てみましょう。

def log1(func):
    def wrapper(*args):
        print("logloglog")
        func(*args)
    return wrapper

@log1
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

triple_sum(100,200,300)

ここに画像の説明を挿入
関数のネストを使用して、デコレーターのパラメーターの受け渡しを完了します。

2. パラメータを使用したデコレータ

さらに、デコレータ自体もパラメータを運ぶことができます。さらにもう 1 レベル、関数のネストを使用します。

def log_with_args(arg1,arg2):
    def log1(func):
        def wrapper(*args):
            print("logloglog")
            func(*args)
            print("arg1 is ",arg1,", args2 is ", arg2)
        return wrapper
    return log1

@log_with_args("hello","world")
def triple_sum(a, b, c):
    print("the sum is ", (a + b + c))

triple_sum(111,222,333)

ここに画像の説明を挿入

終わり

上記はデコレーターの内容全体です。コメント エリアで連絡や修正を歓迎します。

参考

  1. 初心者向けチュートリアル Python 関数デコレーター
  2. 素晴らしい記事、非常に明確

おすすめ

転載: blog.csdn.net/ptyp222/article/details/103703802