【Python】よく使う標準デコレータ6つの使い方

■概要

Pythonのデコレータ(decorator)は、関数やメソッドに「機能を追加する」ための仕組みであり、コードの再利用や整理に便利。

▼基本的な使い方

デコレータは、関数を引数に取り、新しい関数を返す関数

・サンプルコード

def my_decorator(func):
    def wrapper():
        print("処理の前")
        func()
        print("処理の後")

    return wrapper


@my_decorator
def say_hello():
    print("こんにちは")


if __name__ == '__main__':
    say_hello()

・実行結果

処理の前
こんにちは
処理の後
  • @my_decoratorsay_hello = my_decorator(say_hello) と同じ
  • wrapper() の中で、元の func() を呼び出すことで、処理の前後に何かを挿入可能

■よく使う標準デコレータ

以下によく使う標準デコレータ6つを示す。

標準デコレータ概要
@staticmethod静的メソッド
@classmethodクラスメソッド
@propertyプロパティ
@functools.lru_cache関数結果のキャッシュ
@dataclasses.dataclassデータ構造化
@abstractmethod抽象メソッド

▼@staticmethod(静的メソッド)

インスタンス (self) やクラス (cls) に関係ない、ユーティリティ関数的なメソッドを定義したいとき使用。

・サンプルコード

class Math:
    # インスタンス (self) やクラス (cls) に関係ない
    # ユーティリティ関数的なメソッドを定義
    @staticmethod
    def add(x, y):
        return x + y


if __name__ == '__main__':
    print(Math.add(3, 5))

・実行結果

8

▼@classmethod(クラスメソッド)

クラス自体を操作したいとき(例:別のコンストラクタを定義したいとき)使用。

・サンプルコード

class Person:
    def __init__(self, name):
        self.name = name

    # クラス自体を操作したいとき
    # (例:別のコンストラクタを定義したいとき)
    @classmethod
    def from_dict(cls, data):
        return cls(data["name"])


if __name__ == '__main__':
    p = Person.from_dict({"name": "太郎"})
    print(p.name)

・実行結果

太郎

▼@property(プロパティ)

関数をフィールド(属性)のようにアクセスさせたいとき使用。

・サンプルコード

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

    # 関数をフィールド(属性)のようにアクセス
    @property
    def area(self):
        return 3.14 * self._radius ** 2


if __name__ == '__main__':
    c = Circle(5)
    # 関数だが属性のようにアクセスできる: 「()」を使用しない
    print(c.area)

・実行結果

78.5

▼@functools.lru_cache(関数結果のキャッシュ)

再計算のコストが高い関数をキャッシュして高速化したいとき使用。

・サンプルコード

from functools import lru_cache


# 再計算のコストが高い関数をキャッシュして高速化
@lru_cache(maxsize=128)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)


if __name__ == '__main__':
    # 高速に計算される
    print(fib(30))

・実行結果

832040

▼@dataclasses.dataclass(データ構造化)

クラスを簡潔にデータ構造として定義したいとき使用。

・サンプルコード

from dataclasses import dataclass


# クラスを簡潔にデータ構造として定義
# 自動で __init__, __repr__, __eq__ などを生成
@dataclass
class Point:
    x: int
    y: int


if __name__ == '__main__':
    p = Point(1, 2)
    print(p)

・実行結果

Point(x=1, y=2)

▼@abstractmethod(抽象メソッド)

サブクラスで必ずオーバーライドさせたいメソッドを定義するとき使用。

・サンプルコード

from abc import ABC, abstractmethod


class Animal(ABC):
    # サブクラスで必ずオーバーライドさせたいメソッドを定義
    @abstractmethod
    def speak(self):
        pass


class Dog(Animal):
    def speak(self):
        return "ワン!"


if __name__ == '__main__':
    dog = Dog()
    print(dog.speak())

・実行結果

ワン!

コメント