logo

Python のデコレータ

デコレーター は、プログラマが関数やクラスの動作を変更できるため、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))>