概要
Pythonにおけるデコレータ(@decorator
)は、
関数やクラスの振る舞いを動的に拡張・制御する高次関数的手法である。
本稿ではその基本構文から、ログ出力・認可制御・キャッシュ・再試行といった実務的ユースケースまで、
関数設計をより宣言的に、洗練された形で表現するための方法論としてデコレータを徹底解剖する。
1. デコレータの本質:関数を返す関数
def decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@decorator
def greet(name):
return f"Hello, {name}"
→ @decorator
は greet = decorator(greet)
と同義
→ クロスカッティング関心(ログ・検証・権限チェックなど)を外出し可能
2. functools.wraps の役割
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
→ wraps
を使うことで元関数の __name__
や __doc__
を保持
→ デバッグ・ドキュメント・IDE補完を損なわない
3. 引数付きデコレータ
def log(level):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"[{level}] {func.__name__} called")
return func(*args, **kwargs)
return wrapper
return decorator
@log("INFO")
def process():
pass
→ デコレータ自体をファクトリ関数にすることで、柔軟なパラメータ化が可能
4. 実務的ユースケース
✅ ログ出力・トレース
def traced(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"TRACE: {func.__name__}({args}, {kwargs})")
return func(*args, **kwargs)
return wrapper
✅ 認可制御(認証済ユーザーのみ)
def require_login(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not current_user.is_authenticated:
raise PermissionError("Login required")
return func(*args, **kwargs)
return wrapper
✅ キャッシュ処理
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
✅ 再試行制御
def retry(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for i in range(times):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"Retry {i+1}/{times} failed: {e}")
raise RuntimeError("Max retries exceeded")
return wrapper
return decorator
5. クラスメソッドへの適用
class Service:
@traced
def run(self):
print("Service running")
→ インスタンスメソッド、クラスメソッド、スタティックメソッドすべてに対応可能
6. クラスデコレータ(高度設計)
def register(cls):
registry[cls.__name__] = cls
return cls
@register
class Controller:
...
→ クラスレベルのメタ設計(DIコンテナ・プラグイン構築など)に応用される
よくある誤用と対策
❌ デコレータ内で副作用が多すぎる
→ ✅ ラップ関数は副作用を最小限かつ明示的に設計する
❌ wraps
を忘れてデバッグ困難に
→ ✅ functools.wraps
は必須。誰が呼ばれているのかを明示せよ
❌ 再利用性のないデコレータが乱立
→ ✅ 汎用性とドメイン特化を切り分け、共通化可能なロジックは統合
結語
Pythonのデコレータは、単なる構文的糖衣ではない。
それは 関数の意味的拡張を、構文として明示的に記述するための設計構造 である。
- 宣言的な設計
- クロスカッティングな責務分離
- 再利用性とメタ設計の高度化
Pythonicとは、“動作よりも意図を記述する” ことであり、
デコレータはその思想を静かに、かつ強力に具現化する文法である。