Pythonデコレータの使い方:@propertyや@staticmethodを徹底解説

Pythonのデコレータについて、基本的な使い方から@propertyや@staticmethodなどの組み込みデコレータ、独自デコレータの作成方法まで実例付きで解説。メタプログラミングの第一歩を学ぼう。

Pythonデコレータ@property@staticmethod高階関数メタプログラミング2026/5/25

Pythonデコレータとは?

デコレータは、関数やクラスの動作を拡張・変更するためのPythonの機能です。関数を引数に取り、新しい関数を返す「高階関数」の一種で、既存のコードを書き換えずに機能を追加できます。@ 記号を使って簡潔に記述できるため、コードの可読性が向上します。

デコレータの基本構文

<h1>デコレータ関数の定義</h1>
def my_decorator(func):
    def wrapper():
        print("前処理")
        func()
        print("後処理")
    return wrapper

<h1>デコレータの使用</h1> @my_decorator def hello(): print("Hello!")

hello() <h1>出力:</h1> <h1>前処理</h1> <h1>Hello!</h1> <h1>後処理</h1>

@my_decoratorhello = my_decorator(hello) と同じ意味です。

組み込みデコレータ:@property

@property は、メソッドを属性のようにアクセスできるようにするデコレータです。ゲッター、セッター、デリーターを定義できます。

基本的な使い方

class Circle:
    def __init__(self, radius):
        self._radius = radius

@property def radius(self): """半径を取得""" return self._radius

@radius.setter def radius(self, value): if value <= 0: raise ValueError("半径は正の数でなければなりません") self._radius = value

@radius.deleter def radius(self): print("半径を削除します") del self._radius

@property def area(self): return 3.14159 * self._radius ** 2

c = Circle(5) print(c.radius) # 5 c.radius = 10 print(c.area) # 314.159 <h1>del c.radius # 半径を削除します</h1>

  • @property でゲッター、@radius.setter でセッター、@radius.deleter でデリーターを定義。
  • メソッドを属性のように扱えるため、内部実装を隠蔽しつつ、値の検証などのロジックを追加できます。
  • 組み込みデコレータ:@staticmethod

    @staticmethod は、インスタンスやクラスに依存しないメソッドを定義します。通常の関数と同じですが、クラス内に定義することで名前空間を整理できます。

    class MathUtils:
        @staticmethod
        def add(a, b):
            return a + b
    

    @staticmethod def multiply(a, b): return a * b

    print(MathUtils.add(3, 4)) # 7 print(MathUtils.multiply(3, 4)) # 12

  • インスタンス化せずに呼び出せる。
  • 第一引数に selfcls を取らない。
  • ユーティリティ関数をクラス内にまとめるのに便利。
  • @classmethod との違い

    @classmethod は第一引数にクラス自体(cls)を受け取るため、クラス変数にアクセスできます。

    class MyClass:
        class_var = "クラス変数"
    

    @classmethod def class_method(cls): print(f"クラスメソッド: {cls.class_var}")

    MyClass.class_method() # クラスメソッド: クラス変数

    独自デコレータの作成

    引数なしデコレータ

    def timer(func):
        import time
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            print(f"{func.__name__} の実行時間: {end - start:.4f}秒")
            return result
        return wrapper
    

    @timer def long_running_task(): sum(range(1000000))

    long_running_task()

    引数付きデコレータ

    デコレータ自体に引数を渡したい場合は、さらに外側の関数でラップします。

    def repeat(n):
        def decorator(func):
            def wrapper(*args, **kwargs):
                for _ in range(n):
                    result = func(*args, **kwargs)
                return result
            return wrapper
        return decorator
    

    @repeat(3) def greet(name): print(f"Hello {name}!")

    greet("Alice") <h1>Hello Alice!</h1> <h1>Hello Alice!</h1> <h1>Hello Alice!</h1>

    デコレータとメタプログラミング

    デコレータは、関数やクラスの振る舞いを動的に変更する「メタプログラミング」の一手法です。以下のような応用が可能です。

    クラスデコレータ

    クラスにもデコレータを適用できます。

    def add_repr(cls):
        def __repr__(self):
            return f"{cls.__name__}({self.__dict__})"
        cls.__repr__ = __repr__
        return cls
    

    @add_repr class Point: def __init__(self, x, y): self.x = x self.y = y

    p = Point(1, 2) print(p) # Point({'x': 1, 'y': 2})

    関数の属性を利用したデコレータ

    functools.wraps を使うと、ラッパー関数に元の関数の属性(__name____doc__ など)をコピーできます。

    from functools import wraps
    

    def my_decorator(func): @wraps(func) def wrapper(*args, **kwargs): """ラッパー関数""" print("前処理") return func(*args, **kwargs) return wrapper

    @my_decorator def example(): """元の関数""" pass

    print(example.__name__) # example(@wrapsがないとwrapper) print(example.__doc__) # 元の関数

    実践的なデコレータの例

    アクセス制御

    def require_admin(func):
        @wraps(func)
        def wrapper(user, *args, **kwargs):
            if not user.get("is_admin"):
                raise PermissionError("管理者権限が必要です")
            return func(user, *args, **kwargs)
        return wrapper
    

    @require_admin def delete_user(admin, user_id): print(f"ユーザー {user_id} を削除")

    キャッシュ(メモ化)

    def memoize(func):
        cache = {}
        @wraps(func)
        def wrapper(*args):
            if args not in cache:
                cache[args] = func(*args)
            return cache[args]
        return wrapper
    

    @memoize def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2)

    まとめ

  • デコレータは @ 構文で関数やクラスに機能を追加する。
  • @property で属性アクセスを制御、@staticmethod で静的メソッドを定義。
  • 独自デコレータを作成してコードの再利用性を高める。
  • functools.wraps でデコレートされた関数のメタデータを保持。
  • メタプログラミングの強力なツールとして、適切に使うことでクリーンなコードを実現。
  • デコレータをマスターすれば、Pythonプログラミングの幅が大きく広がります。ぜひ実際のコードで試してみてください。