1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

手を動かして理解するデコレータ

Last updated at Posted at 2024-05-09

背景

デコレータを見たことがあるのですが、なんとなくの理解の為ここで苦手意識を克服します!

デコレータとは

関数を引数に受け取り、別の関数を返す関数です。
高階関数というそうです。

デコレータのサンプル

# 関数を引数に受け取り別の関数を返す関数
def decorator_func(f):
    def another_f():
        print('--decorator--start')
        f()
        print('--decorator--end')
    return another_f;

# 関数に渡される関数
def f():
    print(0)

# 呼び出す
decorator_func(f)()
# --decorator--start
# 0
# --decorator--end

ここで以下を書き換えます。

# 関数に渡される関数
def f():
    print(0)

# 呼び出す
decorator_func(f)()
# --decorator--start
# 0
# --decorator--end


関数に渡される関数fの定義の上に@デコレータ関数名つまり、@decorator_funcを書き加えます。

@decorator_func
def f():
    print(0)
# 呼び出す
f()
# --decorator--start
# 0
# --decorator--end

確かに結果が同じになりました。
つまり、@デコレータ関数名高階関数のシンタックスシュガーです。

複数のデコレータを実装する

# デコレータ関数1
def decorator_func_1(f):
    def another_f_1():
        print('--decorator-1--start')
        f()
        print('--decorator-1--end')
    return another_f_1;

# デコレータ関数2
def decorator_func_2(f):
    def another_f_2():
        print('--decorator-2--start')
        f()
        print('--decorator-2--end')
    return another_f_2;

# 関数に渡される関数
@decorator_func_1
@decorator_func_2
def f():
    print(0)
# 呼び出す
f()
# --decorator-1--start
# --decorator-2--start
# 0
# --decorator-2--end
# --decorator-1--end

つまり、
処理としては以下になっていると考えられます。
decorator_func_1が呼び出される

another_f_1が返される

decorator_func_2にanother_f_1が渡される

decorator_func_2がanother_f_2を返す

上から順にデコレータ関数が実行されます。

つまり、以下と同じです。

# デコレータ関数1
def decorator_func_1(f):
    def another_f_1():
        print('--decorator-1--start')
        f()
        print('--decorator-1--end')
    return another_f_1;

# デコレータ関数2
def decorator_func_2(f):
    def another_f_2():
        print('--decorator-2--start')
        f()
        print('--decorator-2--end')
    return another_f_2;

# 関数に渡される関数
def f():
    print(0)

decorator_func_2(decorator_func_1(f))()
# --decorator-1--start
# --decorator-2--start
# 0
# --decorator-2--end
# --decorator-1--end

デコレータに引数を渡す

# デコレータ関数
def decorator_func(args):
    def another_f(f):
        print('--decorator---start')
        f()
        print(args)
        print('--decorator---end')
    return another_f;

# 関数に渡される関数
def f():
    print(0)

# 呼び出す
decorator_func(1)(f)
# --decorator--start
# 0
# 1
# --decorator--end

これはつまり、以下と同じです。

# デコレータ関数
def decorator_func(args):
    def another_f(f):
        print('--decorator---start')
        f()
        print(args)
        print('--decorator---end')
    return another_f;

# 関数に渡される関数
@decorator_func(1)
def f():
    print(0)

# 呼び出す
f
# --decorator--start
# 0
# 1
# --decorator--end

参考

最後に

  • デコレータの苦手意識が少し解消されました
  • 動かしてみると理解しやすいなと感じました

次回の記事
@wrapsについて記事を書きます!
https://docs.python.org/3/library/functools.html#functools.wraps

また、デコレータの使い時についても理解したいです。
TypeScriptでも書いてみたいです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?