Pythonでよく使う実用的なデコレータ10選

Pythonのデコレータは、関数やクラスの挙動を変更・拡張するための強力な機能です。元のコードを変更せずに、共通の処理(例:計測、ログ出力、キャッシュなど)を横断的に適用できます。以下に、実務や学習で役立つ代表的なデコレータを紹介します。

1. 実行時間計測デコレータ

import time

def measure_time(func):
    def inner(*args, **kwargs):
        t0 = time.perf_counter()
        res = func(*args, **kwargs)
        elapsed = time.perf_counter() - t0
        print(f"{func.__name__} took {elapsed:.4f} seconds")
        return res
    return inner

@measure_time
def sample_task():
    time.sleep(0.5)

sample_task()

2. 関数呼び出しログ記録デコレータ

import logging

logging.basicConfig(level=logging.DEBUG)

def log_calls(func):
    def inner(*args, **kwargs):
        logging.debug(f"→ {func.__name__}{args}")
        result = func(*args, **kwargs)
        logging.debug(f"← {func.__name__} → {result}")
        return result
    return inner

@log_calls
def compute(x, y):
    return x * y

compute(4, 7)

3. 結果キャッシュデコレータ(LRU)

from functools import lru_cache

@lru_cache(maxsize=128)
def factorial(n):
    if n <= 1:
        return 1
    return n * factorial(n - 1)

print(factorial(10))  # 初回計算後、再呼び出し時はキャッシュ利用

4. 引数型チェックデコレータ

def enforce_types(*types):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for val, expected in zip(args, types):
                if not isinstance(val, expected):
                    raise TypeError(f"Expected {expected}, got {type(val)}")
            return func(*args, **kwargs)
        return wrapper
    return decorator

@enforce_types(int, str)
def repeat(count, text):
    return text * count

print(repeat(3, "hi"))

5. シングルトンパターン実装デコレータ

def singleton(cls):
    instances = {}
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class DatabaseConnection:
    def __init__(self):
        self.connected = True

db1 = DatabaseConnection()
db2 = DatabaseConnection()
print(db1 is db2)  # True

6. 例外発生時にリトライするデコレータ

import time
import random

def retry(max_attempts=3, delay=0.5):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    time.sleep(delay)
            return None
        return wrapper
    return decorator

@retry(max_attempts=2)
def unstable_api():
    if random.choice([True, False]):
        raise ConnectionError("Network glitch")
    return "OK"

print(unstable_api())

7. 関数のパフォーマンスプロファイリングデコレータ

import cProfile
import pstats

def profile_func(func):
    def wrapper(*args, **kwargs):
        profiler = cProfile.Profile()
        profiler.enable()
        result = func(*args, **kwargs)
        profiler.disable()
        stats = pstats.Stats(profiler)
        stats.sort_stats('cumulative').print_stats(5)
        return result
    return wrapper

@profile_func
def heavy_computation(n):
    return sum(i * i for i in range(n))

heavy_computation(100000)

8. 認証チェックデコレータ

def require_auth(authenticated=True):
    def decorator(func):
        def wrapper(*args, **kwargs):
            if not authenticated:
                raise PermissionError("Authentication required")
            return func(*args, **kwargs)
        return wrapper
    return decorator

# 仮の認証状態
current_user_authenticated = True

@require_auth(authenticated=current_user_authenticated)
def view_dashboard():
    return "Dashboard loaded"

print(view_dashboard())

9. 非同期処理ラッパーデコレータ

import asyncio

def async_wrapper(func):
    async def inner(*args, **kwargs):
        print("Async task started")
        result = await func(*args, **kwargs)
        print("Async task completed")
        return result
    return inner

@async_wrapper
async def fetch_data():
    await asyncio.sleep(1)
    return {"status": "success"}

asyncio.run(fetch_data())

10. 入力値バリデーションデコレータ

def validate_range(min_val=0, max_val=100):
    def decorator(func):
        def wrapper(value):
            if not min_val <= value <= max_val:
                raise ValueError(f"Value must be between {min_val} and {max_val}")
            return func(value)
        return wrapper
    return decorator

@validate_range(10, 50)
def set_brightness(level):
    print(f"Brightness set to {level}")

set_brightness(30)

タグ: Python decorator functional-programming MetaProgramming asyncio

6月18日 19:12 投稿