Blog Post

Python デコレータ 基礎編


作成日 2023-02-09

目次

概要

本記事では Python デコレーターの基礎について解説します。

デコレーターとは

特定の関数に対して前後の処理を追加できる関数です。 @ 見かけるかと思いますが、このことです。 特定の関数をほぼ上書きします。 Python 初心者だと初見でなんじゃと思うかもしれませんが、本記事ではそれについて詳しく解説していきたいと思います。

前知識

改めて Python の関数で何ができるか整理していきましょう。

関数は変数化

Python では関数を一旦適宜したら、変数として扱うことができます。また、その変数自体が関数なので、同様の引数を持ちます。

def increase(a):
    return a + 1

def increase_2(a):
    return a + 2

def get_increase_function(twice):
    if twice:
        return increase_2
    else:
        return increase

some_add = get_increase_function(True)

x = some_add(23) # 25

関数は関数内で定義可能

Python 関数内で関数も定義できます。

def get_increase_function(twice):
    def increase(a):
        return a + 1

    def increase_2(a):
        return a + 2

    if twice:
        return increase_2
    else:
        return increase

some_add = get_increase_function(True)

x = some_add(23) # 25

デコレータなしの実装

上記で関数の扱い方がわかったことから、次に前処理、後処理を追加するとしましょう。

以下が定番なやり方ではないかと思います。

def increase(a):
    return a + 1

def make_sentence_with_idx(idx):
    idx = int(idx)
    num = increase(idx)
    return f"This idx is {num}th(st/nd) element" 

前処理が idx の string 化、後処理が fstring に対応します。

1個であれば上記で十分ですが、例えば以下のように同じ前・後処理があった場合、コードが重複がしてしまいます。

def make_sentence_with_idx_2(idx):
    idx = int(idx)
    num = increase_2(idx)
    return f"This idx is {num}th(st/nd) element" 

def make_sentence_with_idx_3(idx):
    idx = int(idx)
    num = increase_3(idx) # not defined
    return f"This idx is {num}th(st/nd) element" 

前処理、後処理一個でも変更したい場合、全てを書き換える必要が出てきます。 管理・見通し共に悪くなります。 そこで出てくるのが、デコレータです。

デコレータの書き方

定義

デコレータの定義として、基本対象とする関数を第1引数に入れ、それを別の関数でラッピングします。

def decorator(func):

    def rewrite_func(idx):
        idx = int(idx)
        num = func(idx)
        return f"This idx is {num}th(st/nd) element" 

    return rewrite_func

本定義では、func はデコレートしたい関数です。rewrite_func は作り直した関数です。 すると上記で書いた関数は以下のようになります。


# make_sentence_with_idx と等価
@decorator
def increase(a):
    return a + 1

@decorator
def increase_2(a):
    return a + 2

@decorator
def increase_3(a):
    ...

ちなみに上記は以下と等価です。

def increase(a):
    return a + 1
make_sentence_with_idx = decorator(increase)

# 残り割愛

ユースケース

以下のユースケースでは有効かと思われます。

  • 前処理・後処理
  • 処理時間の測定
  • 値・関数の保持・登録
  • 変数の記録

その他

デコレータに対して引数等を用意することもできます。 今回は紹介しませんでしたが、次回以降紹介できれば幸いです。

まとめ

今回デコレータの基本について触れました。また、ユースケース等についても紹介しました。 次回以降は引数の取り方や、functools について記述していこうかと思います。