概要
Decorator(デコレータ)パターンは、
あるオブジェクトや処理に対して、元のコードを変更せずに機能を動的に追加するための構造的デザインパターンである。
Pythonにおける関数・クラスのラップ構造と極めて相性が良く、
ログ出力、認証、キャッシュ、再試行処理などの横断的関心事をシンプルに構築可能となる。
1. なぜDecoratorが必要か?
❌ 機能を拡張するたびに元の関数やクラスを変更する
def process():
log()
auth()
core()
cleanup()
→ 各処理が混在して本質的な処理が埋もれてしまう
✅ 中核の処理を保ったまま、外側から機能を被せる
@logged
@authenticated
def process():
core()
→ 主処理を美しく保ちながら、機能の追加・変更・差し替えが容易に
2. 基本構造(関数デコレータ)
✅ デコレータ関数の定義
def logged(func):
def wrapper(*args, **kwargs):
print(f"[LOG] Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"[LOG] {func.__name__} finished")
return result
return wrapper
✅ デコレータの使用
@logged
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
出力:
[LOG] Calling greet
Hello, Alice!
[LOG] greet finished
3. Python的応用:複数デコレータの組み合わせ
def authenticated(func):
def wrapper(*args, **kwargs):
print("[AUTH] User authenticated")
return func(*args, **kwargs)
return wrapper
@logged
@authenticated
def process_data():
print("Processing data...")
process_data()
→ ログイン・認証・バリデーションなどを段階的にラップできる
4. クラスに対するDecoratorパターン
✅ 抽象DecoratorとConcreteDecoratorによる構造的拡張
class Coffee:
def cost(self):
return 300
class MilkDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost() + 50
class SugarDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost() + 30
coffee = Coffee()
coffee_with_milk = MilkDecorator(coffee)
coffee_full = SugarDecorator(coffee_with_milk)
print(coffee_full.cost()) # 380
→ 装飾の順序で挙動を制御し、柔軟な構成が可能
5. 実務ユースケース
✅ APIのレスポンスキャッシュ処理
→ デコレータで戻り値をメモ化して再計算を回避
✅ 再試行(retry)処理
→ 例外発生時に自動的に再実行するデコレータを実装
✅ タイミング計測・ベンチマーク
→ 実行時間を自動的に記録・可視化
✅ DjangoやFlaskでのビュー関数修飾
→ ログイン制御、認可、CSRF保護などクロスカット処理を集約
6. よくある誤用と対策
❌ デコレータ内部で副作用を起こす
→ ✅ 関心の分離を守り、副作用は明示的に設計
❌ functools.wraps を忘れて関数のメタ情報が失われる
→ ✅ デコレータ定義時に明示的に付加
from functools import wraps
def logged(func):
@wraps(func)
def wrapper(*args, **kwargs):
...
return wrapper
❌ 複雑なネストでデバッグ困難に
→ ✅ 単機能ごとに分離し、テスト可能なデコレータを意識
結語
Decoratorパターンとは、“本体に触れず、機能を柔らかく重ねる洗練された設計”である。
- 関数やオブジェクトの責務を保ったまま、追加機能を柔軟に注入可能
- Pythonでは構文レベルでサポートされており、可読性・再利用性・分離性に優れた実装が可能
- 横断的関心(ログ、認証、キャッシュ、検証)をコードの外側で美しく制御する力
Pythonicとは、“本質を保ちつつ、変化を受け入れる柔軟さ”。
Decoratorパターンはその柔らかな変化を、明示的かつエレガントに実現する技法である。