「@ という記号が関数の上に付いていて、何をしているのか分からない……」。デコレータは、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 デコレータを自分で書いて、動きを確認してみましょう。
ナノトイラボ 
