【Python】デコレーターの使い方(関数の上に@をつけるやつ)

Pythonでデコレーターを使う方法について入門者向けにまとめました。

デコレーターとは?

デコレーター(decorator)とは、関数に追加の処理(前処理・後処理など)を自動的に組み込むための機能です。
関数の定義を変更せずに、機能を拡張できるのが特徴です。「ログ出力」や「認証チェック」など複数の関数に同じ処理を追加したいときに便利です。

使い方はとてもシンプルで、対象の関数の上に @デコレータ名 を書くだけです。

サンプルコード

# デコレータの定義
def decorator(func):
    def wrapper():
        print("前処理")   # 関数の前に実行される処理(元の関数を実行する前のログ保存など)
        func()            # 元の関数を実行
        print("後処理")   # 関数の後に実行される処理(元の関数を実行した後のログ保存など)
    return wrapper

# デコレーターを関数に適用
@decorator
def main():
    print("メイン処理")

# 関数の呼び出し
main()
前処理
メイン処理
後処理
用語 意味
decorator デコレーター関数。処理を追加するための関数
func デコレート対象の関数(この例では main
wrapper() 実際に前後の処理+元の関数をまとめて実行する関数
@decorator main() 関数に decorator を適用する記法

引数付き関数への対応

元の関数に引数がある場合、wrapper()関数*args**kwargs を使うことで、デコレーター側でもその引数を受け取ることができます。

サンプルコード

以下は、関数の引数をデコレーター側で受け取り、if文で動作を条件分岐させる例です。

# デコレーターの定義
def battle_event(func):
    def wrapper(*args, **kwargs):
        print("■戦闘開始!")
        print(f"引数一覧: {args} → ログに保存")
        # キーワード引数を加工(kwargsは辞書)
        if "critical" in kwargs and kwargs["critical"]:
            print("☆クリティカル攻撃発動!")

        func(*args, **kwargs)  # 引数をそのまま渡す
        print("■戦闘終了!")
    return wrapper

# 関数の定義
@battle_event
def attack(name, target, damage, critical=False):
    print(f"{name}は{target} に攻撃し、 {damage} のダメージを与えた!")

# 関数の呼び出し(通常攻撃)
attack("勇者ぴこり", "スライム", 30)

print("勇者ぴこりは前に進む")

# 関数の呼び出し(クリティカル攻撃)
attack("勇者ぴこり", "メタルビー", 100, critical=True)
■戦闘開始!
引数一覧: (‘勇者ぴこり’, ‘スライム’, 30) → ログに保存
勇者ぴこりはスライム に攻撃し、 30 のダメージを与えた!
■戦闘終了!
勇者ぴこりは前に進む
■戦闘開始!
引数一覧: (‘勇者ぴこり’, ‘メタルビー’, 100) → ログに保存
☆クリティカル攻撃発動!
勇者ぴこりはメタルビー に攻撃し、 100 のダメージを与えた!
■戦闘終了!

コード解説

攻撃処理の前後に「戦闘開始」「戦闘終了」などの演出を自動で追加するために、デコレータ関数(battle_eventを定義しています。

def battle_event(func):
    def wrapper(*args, **kwargs):
        print("■戦闘開始!")
        print(f"引数一覧: {args} → ログに保存")
        # キーワード引数を加工(kwargsは辞書)
        if "critical" in kwargs and kwargs["critical"]:
            print("☆クリティカル攻撃発動!")

        func(*args, **kwargs)  # 引数をそのまま渡す
        print("■戦闘終了!")
    return wrapper
  • wrapper() が実際に処理を包み込む関数で、前処理・後処理を追加します。
  • *args**kwargs を使うことで、元の関数の引数を受け取ります。そして、 kwargs["critical"]True のときだけ、if文で特殊演出(☆クリティカル攻撃発動!)を追加します。

複数のデコレーターを重ねがけ

Pythonでは、1つの関数に複数のデコレータを重ねて適用することができます
これにより、前処理・後処理・ログ出力などを段階的に追加できます。

書式

@A
@B
def func():
    ...

上記のように、関数 func に対して2つのデコレーターA``Bを適用すると、以下のように処理されます。

  1. デコレーターBfunc を包む
  2. デコレーターAB(func) をさらに包む
  3. 実行時は A(B(func))() の順で処理される

サンプルコード

# デコレータの定義(魔法詠唱の演出用)
def spell_animation(func):
    def wrapper(*args, **kwargs):
        print("✨ 魔法陣が光り始めた…")
        func(*args, **kwargs)
        print("💥 魔法が炸裂した!")
    return wrapper

# デコレータ(ログ記録用)
def battle_log(func):
    def wrapper(*args, **kwargs):
        print("...ログ記録開始")
        func(*args, **kwargs)
        print("...ログ記録終了")
    return wrapper

# 魔法攻撃用の関数(デコレータを重ねがけ)
@battle_log
@spell_animation
def cast_spell(name, target, spell):
    print(f"{name}は{target} に {spell} を唱えた!")

# 呼び出し
cast_spell("勇者ぴこり", "ゴブリン", "ファイアボール")
…ログ記録開始
✨ 魔法陣が光り始めた…
勇者ぴこりはゴブリン に ファイアボール を唱えた!
💥 魔法が炸裂した!
…ログ記録終了

関連ページ(もっと学びたい人へ)

Pythonの関数の使い方について、以下ページから詳しく学ぶことができます。

【Python超入門】ユーザー定義関数の作り方(def文)
Pythonにおけるユーザー定義関数の作り方(def文)について入門者向けにまとめました。

Pythonの基礎から応用例まで、以下ページから詳しく学ぶことができます。

【Python超入門】基礎から応用例まで幅広く解説
PythonについてPythonは、統計処理や機械学習、ディープラーニングといった数値計算分野を中心に幅広い用途で利用されているプログラミング言語です。他のプログラミング言語と比較して「コードが短くて読みやすい、書きやすい」「ライブラリが豊...
この記事を書いた人
西住技研

プログラミング言語「Python」を研究、仕事、趣味でデータ分析や作業自動化などに活用してきたノウハウを情報発信しています。
筆者の詳しいプロフィールやお問合せはこちらのページまで。
YoutubeX(旧Twitter)でも情報発信中です!

西住技研をフォローする
Python基礎

コメント