Programmingバックエンド開発者

Pythonにおけるデコレーターの仕組みを説明してください。それらの主な利点、実装方法、および使用時に発生する可能性のある注意点は何ですか?

Hintsage AIアシスタントで面接を突破

答え

デコレーターは、他の関数を受け取り、その動作を拡張または変更した新しい関数を返す関数です。ログ記録、権限チェック、キャッシング、実行時間などによく使用されます。

デコレーターは、クロージャー(closure)や、__call__メソッドを実装したクラスを使って実装されます。基本的な構文は次の通りです:

# 簡単なデコレーター def simple_decorator(func): def wrapper(*args, **kwargs): print("関数呼び出し前") result = func(*args, **kwargs) print("関数呼び出し後") return result return wrapper @simple_decorator def my_func(): print("メイン関数") my_func()

結果は次のようになります:

関数呼び出し前
メイン関数
関数呼び出し後

主な利点は、主要なビジネスロジックの外に繰り返しのロジックをカプセル化することです。

注意点:

  • functools.wrapsを使用しないと、元の関数の名前とdocstringが失われます。
  • デコレーターが引数を受け取る場合、関数は三重のネストが必要になります。

トリックのある質問

質問: "もし私がデコレーターで関数をデコレートし、その後__name__を通じて関数名を取得しようとしたら、何が見え、元の名前を保存するにはどうすればよいですか?"

答え:

デフォルトでは、名前はラッパーの名前(通常はwrapper)に変更されます。元のメタデータを保持するには、functools.wrapsを使用します:

import functools def dec(f): @functools.wraps(f) def wrapper(*args): return f(*args) return wrapper @dec def foo(): pass print(foo.__name__) # 'foo'と表示され、'wrapper'ではない

知識の不足による実際のエラーの例


物語

大規模なリソース自動化において、デコレーターで関数をラップした後、テスト関数の名前に対するリフレクションを使用する自動テストシステムが壊れました。問題はfunctools.wrapsが不足していたことです。


物語

ロギングを追加するデコレーターは、異なるシグネチャを持つ関数をサポートしていませんでした。*args, **kwargsを使用しなかったため、いくつかの関数がSilent Failで壊れました。


物語

REST APIにおける認証プロジェクトで、開発者はパラメータのあるデコレーターを実装しましたが、関数を正しくネストするのを忘れました(二重のネストがあり、三重になっていない)。その結果、デコレーターはパラメータを受け取ることができませんでした。