Python で複数のデコレータを実装する

Jay Shaw 2023年10月10日
  1. デコレーターの実装: ファーストクラス オブジェクトとして機能する
  2. Python でパラメーター化されたデコレーターを実装する
  3. Python で @ を使用してデコレーターを実装する
  4. Python で複数のデコレータを実装する
  5. まとめ
Python で複数のデコレータを実装する

Python の最も優れた機能の 1つは、デコレータを使用して関数またはクラスの動作を変更できることです。 デコレーターを使用して、既にプログラム内にあるコードでプログラムの一部を変更できます。

デコレータは、実行中にそのプログラムの一部を変更するプログラム内のコード行です。 コンパイル中にプログラムへの変更を引き出すプロセスは、メタプログラミングと呼ばれます。

この記事では、読者はデコレーターの基本、つまり、Python でデコレーターがどのように宣言され、実装され、連結されるかについて説明します。

デコレーターの実装: ファーストクラス オブジェクトとして機能する

構文的には、関数を反復可能なオブジェクトとして別のオブジェクトに渡すことで、デコレータを宣言できます。 これが可能なのは、Python のすべてが第一級のオブジェクトだからです。 したがって、すべての Python コンストラクトをパラメーターとして渡すか、変数に割り当てることができます。

つまり、すべてのクラス、関数、および宣言された変数をオブジェクトとして渡すことができます。 以下の例は、これを示しています。

コード:

def func():
    def inner():
        print("Chocolate")

    return inner


taste = func()
taste()

出力:

"C:\Users\Win 10\main.py"
Chocolate

Process finished with exit code 0

ここでは、親関数 func() が内部関数 inner() を持つ入れ子関数が作成されます。 inner() 関数は、ステートメントを出力し、関数内で自分自身を返します。

デコレータ関数 func() は、そのデータを空のオブジェクト関数 taste に渡します。 このように飾っています。

このオブジェクト関数に何らかの機能がある場合、デコレーターはそれにも変更を加えます。 この記事の後半では、関数への変更を引き出すためにデコレーターがどのように使用されるかを説明します。

Python では、関数を引数として他の関数に渡したり返したりすることができます。 デコレーターは、関数を引数として受け入れ、この概念を使用して結果を返すこともできます。

以下の例は、パラメーター化されたデコレーターを示しています。 より簡単に理解するには、関数を実世界のオブジェクトと考えてください。

Python でパラメーター化されたデコレーターを実装する

デコレーターが他の関数をパラメーター化された引数として受け取る方法を理解するために、ベーカリーの例を紹介します。

ここで、bakery はオブジェクト関数 obj_func() をパラメーターとして受け取るパラメーター化されたメソッドです。 このメソッド内で、ネストされた関数 inner() が宣言され、Dough を出力します。

その後、obj_func() が呼び出され、inner() 関数が返されます。 オブジェクト関数を呼び出すと、装飾されている関数が呼び出されます。

お分かりのように、bakery は引数 obj_func() を取るパラメータ化されたメソッドであり、これは関数 wheat() にほかならず、inner() 関数が printステートメント。

コード:

def inner():
    print("Dough")
    obj_func()


return inner

装飾されるべきこの関数、つまり wheat には print ステートメントがあります: Turned into pan です。

コード:

def wheat():
    print("Turned into bread")

装飾された関数を格納する新しいオブジェクト関数 final が作成されます。

構文 object_function = decorator(decorated_function) は、inner() 関数のプロパティを実装するパラメーター化されたメソッド bakery にオブジェクトとして渡すことにより、関数 wheat() を装飾します。

コード:

final = bakery(wheat)
final()

装飾された関数は、オブジェクト関数 final に保存されます。 コンパイルされると、プログラムは最初に inner() 関数を実行し、次にオブジェクト関数 wheat() を渡し、その内容を出力する obj_func() を呼び出します。

大雑把に言えば、小麦はベーカリーの中に入れるとパンになり、その結果はパンになりましたと印刷されます。 パン屋が現実世界でどのように働いているかのように!

コード:

def bakery(obj_func):
    def inner():
        print("Dough")
        obj_func()

    return inner


def wheat():
    print("Turned into bread")


final = bakery(wheat)
final()

出力:

"C:\Users\Win 10\main.py"
Dough
Turned into bread

Process finished with exit code 0

Python で @ を使用してデコレーターを実装する

このセグメントは、構文 @function_name を使用して関数を修飾する方法を示しています。 この例では、次のようなプログラムが使用されています。

  • パラメータ化されたネストされた関数。
  • 変数 x と y の間の値をチェックし、分子が分母より小さい場合はそれらを交換する内部関数。
  • 交換された値で装飾される 3 番目の関数は、2つの数値を除算して出力します。

デコレーター関数 decor_func は、オブジェクト関数 obj1 をパラメーターとして受け取ります。 内部では、分母フィールドに大きな数値が指定された場合に値を交換する内部関数が作成されます。

コード:

def decor_func(obj1):
    def swap(x, y):
        pass

内部関数 swap パラメーターは関数 quot パラメーターと同じであるため、obj1 内に格納されたスワップされた値は内部関数から返され、コンパイラーが実行する前に変更された値が関数 quot に渡されます。

この例では、構文 @decor_func が関数 quot の上で宣言されています。 これは、関数 obj1 のパラメーターを受け取り、それらを関数 quot に渡すようにコンパイラーに指示します。

コード:

def decor_func(obj1):
    def swap(x, y):
        if x < y:
            temp = x
            x = x + y - x
            y = y + temp - y
        return obj1(x, y)

    return swap


# Syntax to Decorate function
@decor_func
def quot(x, y):  # Displays quotient of variable x/y
    print(x / y)


quot(2, 4)

出力:

"C:\Users\Win 10\main.py"
2.0

Process finished with exit code 0

Python で複数のデコレータを実装する

デコレーターのチェーン化は、デコレーターを互いに積み重ねて、@function_name が宣言されている回数だけターゲット関数が繰り返し装飾されるようにする手法です。

以下のプログラムでは、decordecor1 という 2つの関数が作成されます。 これらの関数はデコレータであり、算術演算を実行して結果を返す内部関数を持っています。

デコレーターを連鎖させるには、デコレーターを装飾する関数の上で一緒に (互いの上に) 定義する必要があります。 また、コンパイラはデコレータを下から上に読み取ることに注意する必要があります。

これは、関数名のすぐ上に配置されたデコレーターが最初に実装され、その後に他のデコレーターが上に向かって実装されることを意味します。

コード:

@decor  # Gets implemented second
@decor1  # Gets implemented first
def num():
    return 5

以下の例では、関数 num() はデコレーター関数に値を連続して返します。 まず、decor1 は値を受け取り、それをオブジェクト関数 func() に渡し、変更された値を num() に返します。

同様に、このプロセスは他のデコレーター関数でも繰り返されます。 最後に、num() が表示されると、出力として 50 が生成されます。

コード:

# code for testing decorator chaining
def decor1(func):
    def inner():
        x = func()
        return x * x

    return inner


def decor(func):
    def inner():
        x = func()
        return 2 * x

    return inner


@decor
@decor1
def num():
    return 5


print(num())

出力:

"C:\Users\Win 10\main.py"
50

Process finished with exit code 0

まとめ

この記事では、デコレータがプログラムでどのように使用されているかを読者に明確に示しました。 読者は、デコレーターを関数に使用する方法、パラメーターをデコレーターに提供する方法、および複数のデコレーターをチェーンする方法を学ぶ必要があります。

関連記事 - Python Decorator