【Python】デコレータの使い方を初心者向けに徹底解説!@の意味から実用例まで

関数に機能を後付けする仕組みをやさしく解説

※このサイトの記事内では広告を掲載している場合があります。

「@ という記号が関数の上に付いていて、何をしているのか分からない……」。デコレータは、Pythonを学び始めて少し経った頃に出会う壁のひとつです。

この記事では、デコレータを「関数に後から機能を付け足す仕組み」として、関数を引数に渡す考え方から順番に解説します。実際に動くコードと実行結果つきですので、手を動かしながら読み進めてください。

デコレータとは?

デコレータとは、既存の関数のコードを書き換えずに、前後に処理を追加できる仕組みです。たとえば「関数の実行時間を測りたい」「実行前後にログを出したい」といった場面で使われます。

前提として、Pythonでは関数も変数のように扱えます。関数の基本はPythonの関数(def)の書き方で確認しておくと理解しやすくなります。

関数を引数として渡してみる

def hello():
    print("こんにちは")


def call_twice(func):
    func()
    func()


call_twice(hello)
# こんにちは
# こんにちは

call_twice は、受け取った関数を2回呼び出します。このように「関数を受け取る関数」が、デコレータの土台になります。

はじめてのデコレータ

def my_decorator(func):
    def wrapper():
        print("--- 処理開始 ---")
        func()
        print("--- 処理終了 ---")
    return wrapper


@my_decorator
def hello():
    print("こんにちは")


hello()
# --- 処理開始 ---
# こんにちは
# --- 処理終了 ---

@my_decorator と書くと、hello = my_decorator(hello) と書いたのと同じ意味になります。元の hello には手を加えず、前後の処理だけを足せているのがポイントです。

独学で「なぜこれで動くのか」が腑に落ちずに止まってしまったときは、学習方法を見直すのも手です。【徹底比較】Pythonが学べるプログラミングスクールの選び方で、独学とスクールの違いや選び方をまとめています。

引数と戻り値に対応させる

実用的なデコレータは、どんな引数の関数にも使えるよう *args と **kwargs を使います。詳しくは*argsと**kwargsの使い方を参照してください。

def log(func):
    def wrapper(*args, **kwargs):
        print(f"{func.__name__} を呼び出します")
        result = func(*args, **kwargs)
        print(f"結果: {result}")
        return result
    return wrapper


@log
def add(a, b):
    return a + b


add(3, 5)
# add を呼び出します
# 結果: 8

実用例:実行時間を測るデコレータ

import time


def timer(func):
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__}: {elapsed:.4f}秒")
        return result
    return wrapper


@timer
def slow_sum(n):
    return sum(range(n))


slow_sum(1_000_000)
# slow_sum: 0.01秒前後(環境により異なります)

functools.wraps で関数名を保つ

デコレータを使うと、関数の名前が wrapper に置き換わってしまいます。functools.wraps を付けると、元の名前や説明文が保たれます。

from functools import wraps


def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper


@log
def greet():
    """あいさつをする関数"""


print(greet.__name__)  # greet

もっと効率的にPythonを学びたい人へ

デコレータのように抽象的な概念は、読むだけでは分かりにくく、質問できる相手がいると一気に理解が進みます。「自分の書き方で合っているのか不安」という方は、マンツーマンで質問できるスクールも選択肢です。

Winスクールの「Python Winner」は、マンツーマン指導で未経験からPythonを学べ、転職サポートや無料カウンセリングにも対応しています。まずは無料カウンセリングで、自分に合うか確かめてみてはいかがでしょうか。

※本記事には広告(アフィリエイトリンク)を含みます。

Pythonプログラミング|マンツーマンレッスンで初めてをプロに育てる【Python Winner】

他のスクールとも比べたい方は、スクールの比較記事もあわせてご覧ください。資格取得を目指す方はPython3エンジニア認定基礎試験の参考書比較も参考になります。

まとめ

  • デコレータは、関数の前後に処理を足す仕組み
  • @デコレータ名 は func = デコレータ(func) の省略記法
  • どんな関数にも使えるよう *args と **kwargs を受け取る
  • functools.wraps を付けると元の関数名が保たれる
  • 実行時間の計測やログ出力でよく使われる

まずは短い log デコレータを自分で書いて、動きを確認してみましょう。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

CAPTCHA