Pythonのデコレーター(@アットマーク)は何をしているのか

投稿日: 更新日:

デコレーターとは

デコレーターとは関数を修飾するための関数のことです。

ある関数func1を関数decoで修飾するのが以下のコードです。

def deco(func):
    def _wrapper():
        print("start")
        res = func()
        print("end")
        return res

    return _wrapper

@deco
def func1():
    print("func1")
    return "ret"

print(func1())

実行結果

start
func1
end
ret

動作順番

どのような順番で動作しているのか説明します。

  1. deco関数が呼び出される。引数にfunc1が渡される。
  2. deco関数は_wrapper関数を返す。
  3. _wrapper関数を実行する。関数内のfuncは手順1で渡されたfunc1である。
  4. _wrapper関数が値resuを返す。

このような動作手順になります。

デコレーターを書き換えると以下のコードと同等です。func1の上にあった@decoが無くなっていることに注意してください

def deco(func):
    def _wrapper():
        print("start")
        res = func()
        print("end")
        return res

    return _wrapper

def func1():
    print("func1")
    return "ret"

print(deco(func1)())

deco(func1)()は混乱しそうです。しかし、よく考えるとdeco(func1)_wrapper関数を返すことに注目すれば、deco(func1)()_wrapper()と考えれます。

引数を渡す

関数に引数を渡す

func1に引数を渡すこともできます。その場合_wrapper*args**kwargsを引数に指定します

def deco(func):
    def _wrapper(*args, **kwargs):
        print("start")
        res = func(*args, **kwargs)
        print("end")
        return res

    return _wrapper

@deco
def func1(v1):
    print(f"v1: {v1}")
    return "ret"

print(func1(123))

実行結果

start
v1: 123
end
ret

デコレーターに引数を渡す

デコレーターに引数を渡すこともできます。その場合さらに引数を受け取る関数decoで覆います。

def deco(add):
    def _deco(func):
        def _wrapper(*args, **kwargs):
            print("start")
            res = func(*args, **kwargs)
            res += add
            print("end")
            return res

        return _wrapper
    return _deco

@deco(321)
def func1(v1):
    print(f"v1: {v1}")
    return v1

print(func1(123))

実行結果

start
v1: 123
end
444

参考文献

Pythonのデコレータを理解するための12Step https://qiita.com/_rdtr/items/d3bc1a8d4b7eb375c368

(最終閲覧:2022/08/26)

書いた人

profile_image

お茶の葉

物理とプログラミングが好きな人