💬

Pythonデコレータ入門

2023/05/26に公開

Python のデコレータは、関数やメソッドの振る舞いを変更するために使用される特殊な機能です。
デコレータは、関数を引数として受け取り、新しい関数を返す関数です。
デコレータは、@記号を使用して簡単に適用することができます。

デコレータの例
例えば、次のようなデコレータがあります。

def my_decorator(func):
    def wrapper():
        print("Something is happening before the function is called.")
        func()
        print("Something is happening after the function is called.")
    return wrapper

このデコレータは、my_decoratorという名前の関数で定義されています。
この関数は、funcという名前の引数を受け取り、新しい関数wrapperを返します。wrapper関数は、funcが呼び出される前後に何かを行います。

デコレータの適用
このデコレータを使用するには、次のようにします。

@my_decorator
def say_hello():
    print("Hello!")
say_hello()

このコードは、次のような出力を生成します。

Something is happening before the function is called.
Hello!
Something is happening after the function is called.

@記号を使用せずにデコレータを適用することもできます。次のようにします。

def say_hello():
    print("Hello!")
say_hello = my_decorator(say_hello)
say_hello()

このコードも、同じ出力を生成します。

@記号の利点

@記号を使用することで、デコレータの適用が簡単になります。

say_hello = my_decorator(say_hello)

@を適用しない場合、この一行が必要となり、作らなくてもよい変数を実装することになります

クロージャ

クロージャとは、関数内部で定義された関数です。
クロージャは、外部関数のローカル変数にアクセスすることができます。
上記の例では、wrapper関数がクロージャです。
wrapper関数は、外部関数my_decoratorの引数funcにアクセスしています。
デコレータの実装は再利用性があるということがピックアップされて語られることが多いのですが、クロージャという仕組みを理解しなければ外部関数の引数であるfuncを呼び出す理由を思いつくことができません。

今回の実装で言うと、my_decoratorwrapper という関数をreturnし、say_hello() を実行する時点で、中身は wrapper関数 に差し代わっています。
デコレータの動作を一言で表すなら単に 対象オブジェクトを差し替える 技術です。
そしてwrapper関数を実行するわけですが、そのなかにfunc関数があり、そのfuncはどこから参照しているのかというと my_decorator(func)func から参照しているのです。
なぜそれが可能かといえばクロージャーの仕組みを用いて funcsay_hello関数のアドレスを参照するようにし、プログラムが実行可能となっています。

下記の画像はクロージャを使って外部関数に対する値を参照したイメージ図となります

デコレータは、コードの再利用性を高めるために使用されます。
例えば、複数の関数で共通の前処理や後処理が必要な場合、デコレータを使用することで、その処理を一箇所にまとめることができます。

デコレータは非常に強力な機能であり、コードの再利用性や可読性を高めることができます。

Discussion