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

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

# デコレータとは

https://docs.python.org/3/glossary.html#term-decorator

`関数を引数に受け取り、別の関数を返す関数`です。
[高階関数](https://utokyo-ipp.github.io/6/6-2.html#:~:text=%E4%B8%80%E8%88%AC%E3%81%AB%E3%80%81%E9%96%A2%E6%95%B0%E3%82%92%E5%BC%95%E6%95%B0%E3%81%A8%E3%81%97%E3%81%A6%E5%8F%97%E3%81%91%E5%8F%96%E3%81%A3%E3%81%9F%E3%82%8A%E8%BF%94%E5%80%A4%E3%81%A8%E3%81%97%E3%81%A6%E8%BF%94%E3%81%97%E3%81%9F%E3%82%8A%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0%E3%82%92%E9%AB%98%E9%9A%8E%E9%96%A2%E6%95%B0%E3%81%A8%E3%81%84%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)というそうです。

# デコレータのサンプル

https://leetcode.com/playground/hRohr8qD

```python
# 関数を引数に受け取り別の関数を返す関数
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
```
ここで以下を書き換えます。
```python
# 関数に渡される関数
def f():
    print(0)

# 呼び出す
decorator_func(f)()
# --decorator--start
# 0
# --decorator--end
```
↓
関数に渡される関数`f`の定義の上に`@デコレータ関数名`つまり、`@decorator_func`を書き加えます。

https://leetcode.com/playground/DHMJ4oZV

```python
@decorator_func
def f():
    print(0)
# 呼び出す
f()
# --decorator--start
# 0
# --decorator--end
```
確かに結果が同じになりました。
つまり、`@デコレータ関数名`は`高階関数のシンタックスシュガー`です。

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

https://leetcode.com/playground/8muKWH7t

```python
# デコレータ関数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を返す

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

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

https://leetcode.com/playground/oKycEZno

```python
# デコレータ関数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
```

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

https://leetcode.com/playground/TcnJH72J

```python
# デコレータ関数
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
```

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

https://leetcode.com/playground/8fTMZJJB

```python
# デコレータ関数
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

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

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

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