0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するDecoratorパターン:機能の動的付与をシンプルに構築する

Posted at

概要

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パターンはその柔らかな変化を、明示的かつエレガントに実現する技法である。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?