Python でデコレータを作成して使用する方法

Python でデコレータを作成して適用する方法を学びます。ラップ関数、動作の変更、引数の処理、ラップによるメタデータの保持をマスターします。

エディターでこのソリューションを試してください

概要

デコレータは Python の最もエレガントで強力な構文機能の 1 つで、コードを永続的に変更せずに関数またはクラスの動作を変更できます。これらは、実行時間のログ記録、ユーザー認証の強制、結果のキャッシュ (メモ化)、API エンドポイントの監査など、横断的な問題に広く使用されています。

内部では、デコレーターは別の関数を引数として受け取り、カスタム ロジックを挿入する入れ子になったラッパー関数を定義し、このラッパー関数を返す高階関数です。 Python は、関数にデコレータを適用するための「@」記号を使用した簡潔な省略構文を提供し、関数を視覚的にエレガントにします。

デコレータを作成するときは、通常、デコレータ関数で任意の数の位置引数およびキーワード引数をサポートする必要があります。これを実現するには、`*args` と `**kwargs` を受け入れてターゲット関数に渡すようにネストされたラッパー関数を設計します。さらに、元の関数の docstring と名前のメタデータを保存するには、ラッパー関数で `functools.wraps` を使用する必要があります。

コードと実行の出力

このスクリプトは、ロギング デコレータの作成と、入力、出力、およびメタデータを検査する関数のラップを示します。

decorators_tutorial.py
エディターで試してみる
from functools import wraps

# 1. Defining a decorator
def log_execution(func):
    @wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"[Log] Calling function: {func.__name__} with args: {args}")
        result = func(*args, **kwargs)
        print(f"[Log] Finished {func.__name__}. Result: {result}")
        return result
    return wrapper

# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
    """Adds two numbers and returns the sum."""
    return a + b

# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)

# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)
端子出力
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.

段階的な実装

  • ターゲット関数を引数として受け取る外部デコレータ関数を定義します。
  • @functools.wraps(func) をインポートしてネストされたラッパー関数に適用して、元のメタデータを保護します。
  • 入力変数をキャプチャし、ロジックを挿入し、ターゲット関数を呼び出すために、wrapper(*args, **kwargs) を実装します。
  • デコレーターヘッダーブロックからラッパー関数オブジェクトを返します。
  • @decorator_name を使用してデコレータをターゲット関数シグネチャのすぐ上に適用します。

よくある質問

デコレータ内で @functools.wraps が必要なのはなぜですか?

ラップがないと、装飾された関数は元のアイデンティティを失い (その __name__ 属性と __doc__ 属性は、ネストされたラッパー関数の属性に置き換えられます)、デバッグとコードのイントロスペクションが困難になります。

1 つの関数に複数のデコレータを適用できますか?

はい!複数の @ 行を重ねて配置することで、デコレータをチェーンできます。 Python はこれらを下から上に適用します (関数定義に最も近いものが最初に実行されます)。

関連トピック

推奨される Python リソース

関連するインタラクティブなチュートリアル、チートシート、コード比較で知識を深めてください。