0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python】ざっくり見てわかるデコレータの作り方と使い方

Posted at

デコレータとは(ざっくり)

これです
@ がついている子のことをデコレータといいます
デコレーション(装飾)してくれる子です
別名ラッパーと言ったり言わなかったりします
(今回,呼び名自体はなんだっていいので真偽は割愛です)

@handmade_decorator
def just_func(just_hensu):
    print(just_hensu)

何ができるの?

関数の前後に他の処理を入れることができます

やりたいこと.png

どう嬉しいの?

共通の処理を簡潔に適用できます
例えばこんな感じです

  • どの関数も 5 回はリトライするようにしたい
  • 関数実行後に共通したログを出力したい
  • 関数実行前に共通のチェックを入れたい

このようなお悩みを,
関数定義の前に @ を書いてあげるだけで解決するのがデコレータです

今回デコレートする関数の紹介

引数を出力するだけのシンプルな関数です

# デコレートされる関数
def just_func(just_hensu):
    print(just_hensu)

# 通常通り関数を呼び出す
just_func("通常通りの関数")

出力結果はこちらです

通常通りの関数

まずは @ を使わない方法

最初は @ を使いません
後で @ は出てくるので少々辛抱です

ということでまずはこちらをご覧ください

# デコレータ
def handmade_decorator(target_func, hensu):
    print("前処理")
    target_func(hensu)
    print("後処理")


# デコレートされる関数
def just_func(just_hensu):
    print(just_hensu)


# デコレーション
handmade_decorator(just_func, "デコレーション")

出力結果はこうです
「デコレーション」の前に「前処理」,
後に「後処理」を出力するようにしました

前処理
デコレーション
後処理

何が起きたかというと,こうです
簡単な例の説明.png

今回の例ではこうですね
簡単な例の説明2.png
このように,関数の前後に何かしらの処理をいれてくれる
それがデコレータです

関数を返すデコレータ

デコレータの中で関数を定義して,その関数を返すパターンです
ポイントは関数名を変えずに,前後に処理を追加できるところです

# デコレータ
def handmade_decorator(target_func):
    """関数を定義してその関数を返す"""

    def wrap_func(hensu):
        print("前処理")
        target_func(hensu)
        print("後処理")

    return wrap_func

# デコレートされる関数
def just_func(just_hensu):
    print(just_hensu)

# デコレートされた後
just_func = handmade_decorator(just_func)
just_func("デコレーション")

出力例は先ほどと同様です
変わったのは下記です

  • デコレータの中で関数を定義してそれを返す
  • デコレータから返ってきた関数を変数(just_func)に入れる
  • 返ってきた関数(just_func)を呼び出す

デコレータの中で関数を定義してそれを返す?
何を言ってるのかしら...ということでこちら解説です
関数を返す例1_2.png

デコレータから返ってきた関数を変数(just_func)に入れる?
返ってきた関数(just_func)を呼び出す?
何を言っちゃているの...?ということで解説です

関数を返す例2_1.png

イメージでいうとこんな感じですね
関数を返す例3_1.png

ということで元々の just_func 関数を,
デコレータ handmade_decorator によって装飾し,
変数 just_func に返したわけです

ここ大事なのは,
元々の just_func と変数 just_func同姓同名の違う子ということです

デコレートされる前後で id と正体を確認してみます
丸っきり違う子だということがわかりますね

# デコレートされる前
print(id(just_func)) # 2121628872320
print(just_func) # <function just_func at 0x000001EDFAEF6E80>

# デコレートされた後
just_func = handmade_decorator(just_func)

print(id(just_func)) # 2121628867840
print(just_func) # <function handmade_decorator.<locals>.wrap_func at 0x000001EDFAEF5D00>

@を使ってデコレーション

お待たせしました
@の登場です

この@を使った書き方は糖衣構文といい,
かっこよく言うとシンタックスシュガーです
先ほどまでの書き方だと書くのが大変ということで,
書きやすくしたのが糖衣構文ってやつですね
飲みやすくするために甘いもので包んだお薬も糖衣っていいますよね
(某xx丸みたいな)

ということで見ていきましょう

"""シンタックスシュガー"""

# デコレータ
def handmade_decorator(target_func):

    def wrap_func(hensu):
        print("前処理")
        target_func(hensu)
        print("後処理")

    return wrap_func

# デコレートされる関数
@handmade_decorator
def just_func(just_hensu):
    print(just_hensu)

# デコレートされた関数を呼び出す
just_func("デコレーション")

出力結果は変わらないので割愛です

これまでと変わったのは以下です

  • just_func の上に @handmade_decorator がついている
  • just_func = handmade_decorator(just_func) が無くなっている

そしてポイントはまさにここです

# @をつけるだけでデコレーションできる
@handmade_decorator
def just_func(just_hensu):
    print(just_hensu)

# 既にデコレーションされてるので後はそのまま呼び出すだけ
just_func("デコレーション")

デコレータに引数を渡したい

@handmade_decorator(arg) みたいな感じで,
デコレータに引数を渡したい場合です

そのためには,デコレータを返す関数をつくります
下記の例だと create_decorator がそれです

crete_decoratorhandmade_decorator を定義して返し,
handmade_decoratorwrap_func を定義して返す
という流れです

"""デコレータに引数を渡したい"""

# デコレータを返す関数
def create_decorator(arg):
    # デコレータ
    def handmade_decorator(target_func):

        def wrap_func(hensu):
            print(arg) # 引数でもらってきた arg をここで出力
            print("前処理")
            target_func(hensu)
            print("後処理")

        return wrap_func
    return handmade_decorator


# デコレートされる関数
# デコレータに arg をわたしてます
@create_decorator(arg="デコレータに渡す引数")
def just_func(just_hensu):
    print(just_hensu)

# デコレートされた関数を呼び出す
just_func("デコレーション")

出力結果はこうです

デコレータに渡す引数
前処理
デコレーション
後処理

参考

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?