2
2

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におけるデコレータの全貌:構文・応用・関数設計の洗練

Posted at

概要

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}"

@decoratorgreet = 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とは、“動作よりも意図を記述する” ことであり、
デコレータはその思想を静かに、かつ強力に具現化する文法である。

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?