背景
デコレータを見たことがあるのですが、なんとなくの理解の為ここで苦手意識を克服します!
デコレータとは
関数を引数に受け取り、別の関数を返す関数
です。
高階関数というそうです。
デコレータのサンプル
# 関数を引数に受け取り別の関数を返す関数
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
参考
- https://zenn.dev/ryo_kawamata/articles/learn_decorator_in_python
- https://programming-surgeon.com/python/grammer/python-decorator/
- https://utokyo-ipp.github.io/6/6-2.html
最後に
- デコレータの苦手意識が少し解消されました
- 動かしてみると理解しやすいなと感じました
次回の記事
@wraps
について記事を書きます!
https://docs.python.org/3/library/functools.html#functools.wraps
また、デコレータの使い時についても理解したいです。
TypeScriptでも書いてみたいです。