工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Industrial programming >> Python

Python デコレータ

Python デコレータ

デコレータは関数を受け取り、いくつかの機能を追加して返します。このチュートリアルでは、デコレーターを作成する方法と、デコレーターを使用する理由を学びます。

ビデオ:Python の @Decorators

Python のデコレータ

Python には デコレータ という興味深い機能があります 既存のコードに機能を追加します。

これはメタプログラミングとも呼ばれます コンパイル時に、プログラムの一部がプログラムの別の部分を変更しようとするためです。


デコレータを学習するための前提条件

デコレーターについて理解するには、まず Python の基本的なことをいくつか知っておく必要があります。

Python のすべて (はい! クラスでさえも) がオブジェクトであるという事実に慣れる必要があります。私たちが定義する名前は、これらのオブジェクトにバインドされた単なる識別子です。関数も例外ではなく、オブジェクトでもあります (属性付き)。さまざまな名前を同じ関数オブジェクトにバインドできます。

以下に例を示します。

def first(msg):
    print(msg)


first("Hello")

second = first
second("Hello")

出力

Hello
Hello

コードを実行すると、両方の関数 firstsecond 同じ出力を与えます。ここでは、名前 first そして second 同じ関数オブジェクトを参照してください。

今、物事は奇妙になり始めています.

関数は別の関数に引数として渡すことができます。

map のような関数を使用した場合 、 filter そして reduce

引数として他の関数を取るそのような関数は、高階関数とも呼ばれます .以下はそのような関数の例です。

def inc(x):
    return x + 1


def dec(x):
    return x - 1


def operate(func, x):
    result = func(x)
    return result

次のように関数を呼び出します。

>>> operate(inc,3)
4
>>> operate(dec,3)
2

さらに、関数は別の関数を返すことができます。

def is_called():
    def is_returned():
        print("Hello")
    return is_returned


new = is_called()

# Outputs "Hello"
new()

出力

Hello

ここでは、is_returned() is_called() を呼び出すたびに定義され、返されるネストされた関数です .

最後に、Python のクロージャについて知っておく必要があります。


デコレータに戻る

関数とメソッドは callable と呼ばれます

実際、特別な __call__() を実装するオブジェクトは、 メソッドは呼び出し可能と呼ばれます。したがって、最も基本的な意味で、デコレータは callable を返す callable です。

基本的に、デコレータは関数を受け取り、いくつかの機能を追加して返します。

def make_pretty(func):
    def inner():
        print("I got decorated")
        func()
    return inner


def ordinary():
    print("I am ordinary")

シェルで次のコードを実行すると、

>>> ordinary()
I am ordinary

>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary

上記の例では、make_pretty() デコレータです。割り当てステップ:

pretty = make_pretty(ordinary)

関数 ordinary() 装飾され、返された関数には pretty という名前が付けられました .

デコレータ関数が元の関数にいくつかの新しい機能を追加したことがわかります。これは、ギフトの梱包に似ています。デコレータはラッパーとして機能します。装飾されたオブジェクト (実際のギフトの中身) の性質は変わりません。しかし、今はきれいに見えます (装飾されているため)。

通常、関数をデコレートし、次のように再割り当てします。

ordinary = make_pretty(ordinary).

これは一般的な構造であり、このため、Python にはこれを単純化する構文があります。

@ を使用できます シンボルをデコレータ関数の名前とともに、装飾する関数の定義の上に配置します。たとえば、

@make_pretty
def ordinary():
    print("I am ordinary")

と同等です

def ordinary():
    print("I am ordinary")
ordinary = make_pretty(ordinary)

これは、デコレータを実装するための単なる構文糖衣です。


パラメータによる関数の装飾

上記のデコレーターは単純で、パラメーターを持たない関数でのみ機能しました。次のようなパラメータを受け取る関数があるとしたらどうなるでしょうか:

def divide(a, b):
    return a/b

この関数には 2 つのパラメーター a があります。 と b . b を渡すとエラーになることがわかっています 0として。

>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero

エラーの原因となるこのケースをチェックするデコレータを作成しましょう。

def smart_divide(func):
    def inner(a, b):
        print("I am going to divide", a, "and", b)
        if b == 0:
            print("Whoops! cannot divide")
            return

        return func(a, b)
    return inner


@smart_divide
def divide(a, b):
    print(a/b)

この新しい実装は None を返します エラー状態が発生した場合。

>>> divide(2,5)
I am going to divide 2 and 5
0.4

>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide

このようにして、パラメータを取る関数を装飾できます。

鋭い観察者は、ネストされた inner() のパラメーターに気付くでしょう。 デコレーター内の関数は、デコレーターが装飾する関数のパラメーターと同じです。これを考慮して、任意の数のパラメーターで動作する一般的なデコレーターを作成できるようになりました。

Python では、この魔法は function(*args, **kwargs) として行われます。 .このように args 位置引数と kwargs のタプルになります キーワード引数の辞書になります。このようなデコレータの例は次のとおりです:

def works_for_all(func):
    def inner(*args, **kwargs):
        print("I can decorate any function")
        return func(*args, **kwargs)
    return inner

Python でのデコレータの連鎖

Python では、複数のデコレータを連鎖させることができます。

つまり、関数は異なる (または同じ) デコレーターで複数回装飾することができます。目的の関数の上にデコレータを配置するだけです。

def star(func):
    def inner(*args, **kwargs):
        print("*" * 30)
        func(*args, **kwargs)
        print("*" * 30)
    return inner


def percent(func):
    def inner(*args, **kwargs):
        print("%" * 30)
        func(*args, **kwargs)
        print("%" * 30)
    return inner


@star
@percent
def printer(msg):
    print(msg)


printer("Hello")

出力

******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Hello
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************

上記の構文

@star
@percent
def printer(msg):
    print(msg)

と同等です

def printer(msg):
    print(msg)
printer = star(percent(printer))

デコレータをチェーンする順序は重要です。順序を逆にすると、

@percent
@star
def printer(msg):
    print(msg)

出力は次のようになります:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
******************************
Hello
******************************
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Python

  1. Python データ型
  2. Python 演算子
  3. Python pass ステートメント
  4. Python 関数の引数
  5. Python 匿名/Lambda 関数
  6. 例を含む Python Lambda 関数
  7. Python abs() 関数:絶対値の例
  8. 例を使用した Python round() 関数
  9. Python range() 関数:Float、List、For ループの例
  10. 例を使用した Python map() 関数
  11. Yield in Python チュートリアル:Generator &Yield vs Return の例