0
1

[Python]デコレーター

Posted at

デコレーター

Pythonのデコレータ(Decorator)は、関数やクラスの機能を簡単に修正または拡張する機能です。通常、関数を扱う高度な機能を実装する際に使用され、関数やメソッドの実行前後にコードを追加したり、関数の返り値を変更したり、例外を処理したりすることができます。

デコレータは、関数で実装され、他の関数を引数として受け取り、内部でそれを変更したり新しい関数を返したりします。通常、@decorator_functionのような形で、関数やメソッドの直前に使用されます。

例として、関数の実行時間を計測するデコレータを示します:

import time

def measure_time(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Execution time: {end_time - start_time} seconds")
        return result
    return wrapper

@measure_time
def some_function():
    time.sleep(1)
    print("Function executed")

some_function()

上記の例では、measure_timeデコレータがsome_function関数を包み込み、実行時間を計測してその値を出力します。@measure_timeを使ってデコレータを適用し、some_function()を呼び出すと、関数の実行前後の時間が出力されます。

デコレータはログ記録、認証および権限の確認、キャッシュ、バリデーションなど、さまざまなタスクに有効に使用できます。複数のデコレータを組み合わせて使用したり、クラスのメソッドにも適用することができます。Pythonのデコレータは、コードをよりきれいで再利用可能にする強力なツールです。

クラスデコレーター

クラスにデコレータを適用する方法について説明します。

Pythonでは、クラスのメソッドにもデコレータを適用することができます。通常の関数の場合と同様に、デコレータは関数として実装され、@decorator_functionのようにメソッドの上に使用されます。

例として、メソッドの実行時間を計測するデコレータをクラスに適用する方法を示します:

import time

def measure_time(method):
    def wrapper(self, *args, **kwargs):
        start_time = time.time()
        result = method(self, *args, **kwargs)
        end_time = time.time()
        print(f"{self.__class__.__name__}.{method.__name__} の実行時間: {end_time - start_time}")
        return result
    return wrapper

class MyClass:
    @measure_time
    def some_method(self):
        time.sleep(1)
        print("メソッドが実行されました")

obj = MyClass()
obj.some_method()

上記の例では、measure_timeデコレータがMyClassクラスのsome_methodメソッドを包み込み、その実行時間を計測して表示します。@measure_timeでデコレータを適用すると、メソッドを呼び出すたびにその実行時間が表示されます。

クラスにデコレータを適用する際の注意点としては、デコレータ関数の第一引数はselfである必要があります。これにより、デコレータがメソッドが属するインスタンスを正しく認識できます。

クラスデコレータは、ログ記録、認証、キャッシュなどの追加機能を実装する際に非常に有用です。これにより、コードの再利用性と可読性を向上させることができます。

よく使うデコレーター

Pythonでよく使用されるデコレータの1つに、@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

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

# Circleクラスの使用例
circle = Circle(5)
print(f"半径: {circle.radius}")
print(f"面積: {circle.area}")

circle.radius = 10
print(f"変更された半径: {circle.radius}")
print(f"変更された面積: {circle.area}")

上記の例では、@propertyデコレータを使用してradiusメソッドをプロパティとしてアクセスできるようにしました。これにより、circle.radiusのように属性のように使用でき、同時に@radius.setterを使用してこの属性に値を設定する際にバリデーションを追加することができます。

@propertyデコレータは、クラスのメソッドを属性のようにアクセス可能にし、属性の設定時に追加のロジックを挿入することができるため、非常に便利です。

0
1
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
1