デコレーター は、プログラマが関数やクラスの動作を変更できるため、Python の非常に強力で便利なツールです。デコレータを使用すると、ラップされた関数を永続的に変更することなく、別の関数をラップしてその動作を拡張できます。ただし、デコレーターについて詳しく説明する前に、デコレーターを学習する際に役立ついくつかの概念を理解しておきましょう。
ファーストクラスのオブジェクト
Python では、関数は次のとおりです。 ファーストクラスのオブジェクト これは、Python の関数を使用したり、引数として渡したりできることを意味します。
ファーストクラス関数のプロパティ:
- 関数はオブジェクト型のインスタンスです。
- 関数を変数に格納できます。
- 関数をパラメータとして別の関数に渡すことができます。
- 関数から関数を返すことができます。
- ハッシュ テーブル、リストなどのデータ構造に保存できます。
より深く理解するために、以下の例を検討してください。
例 1: 関数をオブジェクトとして扱います。
Python3
# Python program to illustrate functions> # can be treated as objects> def> shout(text):> > return> text.upper()> print> (shout(> 'Hello'> ))> yell> => shout> print> (yell(> 'Hello'> ))> |
>
>
出力:
HELLO HELLO>
上の例では、関数 Shout を変数に割り当てています。これは関数を呼び出すのではなく、シャウトによって参照される関数オブジェクトを取得し、それを指す 2 番目の名前、yell を作成します。
例 2: 関数を引数として渡す
Python3
# Python program to illustrate functions> # can be passed as arguments to other functions> def> shout(text):> > return> text.upper()> def> whisper(text):> > return> text.lower()> def> greet(func):> > # storing the function in a variable> > greeting> => func(> '''Hi, I am created by a function passed as an argument.'''> )> > print> (greeting)> greet(shout)> greet(whisper)> |
>
>
出力:
HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.>
上の例では、greet 関数はパラメータとして別の関数 (この場合は叫ぶとささやく) を取ります。引数として渡された関数は、関数greet内で呼び出されます。
例 3: 別の関数から関数を返す。
Python3
Java文字列ビルダー
# Python program to illustrate functions> # Functions can return another function> def> create_adder(x):> > def> adder(y):> > return> x> +> y> > return> adder> add_15> => create_adder(> 15> )> print> (add_15(> 10> ))> |
>
>
出力:
25>
上の例では、別の関数の内部に関数を作成し、内部で作成された関数を返しています。
上記の 3 つの例は、デコレータを理解するために必要な重要な概念を示しています。これらを一通り調べた後、デコレータについて詳しく見ていきましょう。
デコレーター
上で述べたように、デコレータは関数またはクラスの動作を変更するために使用されます。 Decorators では、関数は別の関数の引数として取得され、ラッパー関数内で呼び出されます。
デコレータの構文:
@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)'''>
上記のコードでは、gfg_decorator は呼び出し可能な関数であり、別の呼び出し可能な関数、hello_decorator 関数の先頭にコードを追加し、ラッパー関数を返します。
デコレータは、 行動 :
Python3
# defining a decorator> def> hello_decorator(func):> > # inner1 is a Wrapper function in> > # which the argument is called> > > # inner function can access the outer local> > # functions like in this case 'func'> > def> inner1():> > print> (> 'Hello, this is before function execution'> )> > # calling the actual function now> > # inside the wrapper function.> > func()> > print> (> 'This is after function execution'> )> > > return> inner1> # defining a function, to be called inside wrapper> def> function_to_be_used():> > print> (> 'This is inside the function !!'> )> # passing 'function_to_be_used' inside the> # decorator to control its behaviour> function_to_be_used> => hello_decorator(function_to_be_used)> # calling the function> function_to_be_used()> |
>
>
出力:
Hello, this is before function execution This is inside the function !! This is after function execution>
上記のコードの動作と、function_to_be_used が呼び出されたときにコードがどのように実行されるかを段階的に見てみましょう。
簡単に確認できる別の例に移りましょう 関数の実行時間 デコレータを使用します。
Python3
文字列内のJava int
# importing libraries> import> time> import> math> # decorator to calculate duration> # taken by any function.> def> calculate_time(func):> > > # added arguments inside the inner1,> > # if function takes any arguments,> > # can be added like this.> > def> inner1(> *> args,> *> *> kwargs):> > # storing time before function execution> > begin> => time.time()> > > func(> *> args,> *> *> kwargs)> > # storing time after function execution> > end> => time.time()> > print> (> 'Total time taken in : '> , func.__name__, end> -> begin)> > return> inner1> # this can be added to any function present,> # in this case to calculate a factorial> @calculate_time> def> factorial(num):> > # sleep 2 seconds because it takes very less time> > # so that you can see the actual difference> > time.sleep(> 2> )> > print> (math.factorial(num))> # calling the function.> factorial(> 10> )> |
>
>
出力:
3628800 Total time taken in : factorial 2.0061802864074707>
関数が何かを返したり、関数に引数が渡されたりした場合はどうなるでしょうか?
上記のすべての例では、関数は何も返さなかったので問題はありませんでしたが、戻り値が必要になる場合があります。
Python3
def> hello_decorator(func):> > def> inner1(> *> args,> *> *> kwargs):> > > print> (> 'before Execution'> )> > > # getting the returned value> > returned_value> => func(> *> args,> *> *> kwargs)> > print> (> 'after Execution'> )> > > # returning the value to the original frame> > return> returned_value> > > return> inner1> # adding decorator to the function> @hello_decorator> def> sum_two_numbers(a, b):> > print> (> 'Inside the function'> )> > return> a> +> b> a, b> => 1> ,> 2> # getting the value through return of the function> print> (> 'Sum ='> , sum_two_numbers(a, b))> |
>
>
出力:
before Execution Inside the function after Execution Sum = 3>
上の例では、内部関数のパラメーターに大きな違いがあることに気づくかもしれません。内部関数は引数を *args および **kwargs として受け取ります。これは、位置引数のタプルまたはキーワード引数の辞書を任意の長さで渡すことができることを意味します。これにより、任意の数の引数を持つ関数を装飾できる一般的なデコレーターになります。
デコレータの連鎖
簡単に言えば、デコレータをチェーンすることは、関数を複数のデコレータで装飾することを意味します。
例:
Python3
# 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> @decor1> @decor> def> num():> > return> 10> @decor> @decor1> def> num2():> > return> 10> > print> (num())> print> (num2())> |
>
>
出力:
400 200>
上の例は、関数を次のように呼び出すのと似ています。
decor1(decor(num)) decor(decor1(num2))>