ホームページ >バックエンド開発 >Python チュートリアル >高度な Python デコレータ: コードを強化する

高度な Python デコレータ: コードを強化する

Patricia Arquette
Patricia Arquetteオリジナル
2025-01-06 03:42:48985ブラウズ

Advanced Python Decorators: Elevating Your Code

あなたが賑やかなキッチンのシェフであると想像してみてください。レシピ、いわば機能があります。時間が経つにつれて、ほとんどの料理には、提供する前にオリーブオイル、塩ひとつまみ、またはハーブをふりかける必要があることがわかります。すべての料理にこれらの仕上げを手作業で加えるのではなく、自動的に仕上げてくれるアシスタントがいたら便利だと思いませんか? Python デコレータがコードに対して実行できるのはまさにこれであり、エレガントで再利用可能で表現力豊かな方法で機能を追加できます。

この記事では、高度な Python デコレータの世界を探っていきます。基本を超えて、パラメータ化されたデコレータ、スタック可能なデコレータ、さらにはクラスを備えたデコレータについても詳しく説明します。また、ベスト プラクティスと避けるべき落とし穴についても説明します。準備ができて?料理を始めましょう!

基本を再考する

奥深くに入る前に、基礎を再確認しましょう。 Python のデコレータは、別の関数 (またはメソッド) を引数として受け取り、それを拡張して新しい関数を返す単純な関数です。以下に例を示します:

# Basic decorator example
def simple_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}...")
        result = func(*args, **kwargs)
        print(f"{func.__name__} finished.")
        return result
    return wrapper

@simple_decorator
def say_hello():
    print("Hello, world!")

say_hello()

出力:

Calling say_hello...
Hello, world!
say_hello finished.

さあ、高度な使用例を卒業しましょう。

パラメータ化されたデコレータ

場合によっては、デコレータは独自の引数を受け入れる必要があります。たとえば、さまざまなレベル (INFO、DEBUG、ERROR) でメッセージをログに記録するデコレータが必要な場合はどうなるでしょうか?

# Parameterized decorator example
def log(level):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print(f"[{level}] Calling {func.__name__}...")
            result = func(*args, **kwargs)
            print(f"[{level}] {func.__name__} finished.")
            return result
        return wrapper
    return decorator

@log("INFO")
def process_data():
    print("Processing data...")

process_data()

出力:

[INFO] Calling process_data...
Processing data...
[INFO] process_data finished.

この階層構造 (デコレーターを返す関数) は、柔軟なパラメーター化されたデコレーターを作成するための鍵となります。

積み重ね可能なデコレータ

Python では、複数のデコレータを 1 つの関数に適用できます。デコレータを 2 つ作成して積み重ねてみましょう。

# Stackable decorators

def uppercase(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

def exclaim(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result + "!!!"
    return wrapper

@uppercase
@exclaim
def greet():
    return "hello"

print(greet())

出力:

HELLO!!!

ここでは、デコレータはボトムアップ方式で適用されます。@exclaim が挨拶をラップし、@uppercase が結果をラップします。

クラスをデコレータとして使用する

Python のあまり知られていない機能は、クラスをデコレータとして使用できることです。これは、状態を維持する必要がある場合に特に役立ちます。

# Class-based decorator
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.call_count = 0

    def __call__(self, *args, **kwargs):
        self.call_count += 1
        print(f"Call {self.call_count} to {self.func.__name__}")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()
say_hello()

出力:

Call 1 to say_hello
Hello!
Call 2 to say_hello
Hello!

ここで、call メソッドにより、クラスが関数のように動作できるようになり、ターゲット関数をシームレスにラップできるようになります。

メソッドのデコレータ

デコレータはクラス内のメソッドと同様に機能します。ただし、自分自身を正しく扱うことが不可欠です。

# Method decorator example
def log_method(func):
    def wrapper(self, *args, **kwargs):
        print(f"Method {func.__name__} called on {self}")
        return func(self, *args, **kwargs)
    return wrapper

class Greeter:
    @log_method
    def greet(self, name):
        print(f"Hello, {name}!")

obj = Greeter()
obj.greet("Alice")

出力:

Method greet called on <__main__.Greeter object at 0x...>
Hello, Alice!

デコレーターとコンテキストマネージャーの組み合わせ

場合によっては、デコレータをリソース管理と統合する必要があります。たとえば、関数の実行時間を計測するデコレータを作成してみましょう。

import time

# Timing decorator
def time_it(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.2f} seconds")
        return result
    return wrapper

@time_it
def slow_function():
    time.sleep(2)
    print("Done sleeping!")

slow_function()

出力:

# Basic decorator example
def simple_decorator(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}...")
        result = func(*args, **kwargs)
        print(f"{func.__name__} finished.")
        return result
    return wrapper

@simple_decorator
def say_hello():
    print("Hello, world!")

say_hello()

ベストプラクティス

デコレーターと作業するときは、可読性と保守性を念頭に置くことが重要です。ここにいくつかのヒントがあります:

  • functools.wraps を使用する: これにより、元の関数のメタデータが保存されます。
Calling say_hello...
Hello, world!
say_hello finished.
  • 徹底的にテストする: デコレーターは、特に複数のデコレーターをチェーンする場合に、微妙なバグを引き起こす可能性があります。

  • ドキュメント デコレータ: 各デコレータの動作とその期待されるパラメータを明確に文書化します。

  • 過度の使用を避ける: デコレーターは強力ですが、過度に使用するとコードを理解しにくくなる可能性があります。

まとめ

デコレーターは、Python の最も表現力豊かな機能の 1 つです。これらを使用すると、クリーンで再利用可能な方法で動作を拡張および変更できます。パラメータ化されたデコレータからクラスベースの実装まで、可能性は無限です。スキルを磨くと、デコレーターを活用して、よりクリーンで Python 的なコードを作成できるようになります。そしておそらく、偉大なシェフのように、作成するすべてのレシピに独自のタッチを加えることができます。

注: AI 支援コンテンツ

以上が高度な Python デコレータ: コードを強化するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。