
そして再び、すべての読者に良い一日を!
翻訳の最初の部分に関心をお寄せいただきありがとうございます。2番目の部分も失望させないことを願っています。
そのため、この記事の最初の部分では、デコレーターとその作業の原理について基本的な知識を身に付け、独自に作成しました。
ただし、前に調べたすべてのデコレーターには、非常に重要な機能が1つもありませんでした-装飾される関数に引数を渡します。
さて、この誤解を修正してください!
装飾された関数に引数を渡す(「転送する」)
ブラックマジックはありません。実際に必要なのは、引数を渡すことだけです。
def a_decorator_passing_arguments(function_to_decorate): def a_wrapper_accepting_arguments(arg1, arg2):
*-注 翻訳者:ピーター・ベンクマン- 同じ名前のカルト映画の主人公、ゴーストバスターズの名前 。ドレッシング方法
理解すべき重要な事実の1つは、Pythonの関数とメソッドはほとんど同じことです。ただし、メソッドは常に最初のパラメーターがオブジェクト自体(
self )を参照することを期待しています。 これは、
selfを忘れることなく、関数と同じ方法でメソッドのデコレータを作成できることを意味します。
def method_friendly_decorator(method_to_decorate): def wrapper(self, lie): lie = lie - 3
もちろん、最も一般的なデコレータを作成し、それを任意の関数またはメソッドに適用したい場合、
* argsは
argsリストをアンパックし、
** kwargsは
kwargs辞書をアンパックするという事実を使用する価値が
あります。
def a_decorator_passing_arbitrary_arguments(function_to_decorate):
さまざまな引数でデコレータを呼び出す
素晴らしい、それを整理しました。 異なる引数でデコレータを呼び出そうとすると、あなたは今何を言いますか?
これは見た目ほど単純ではありません。デコレータは関数を引数として受け入れる必要があり、他に何も渡すことができないためです。
そのため、ソリューションを紹介する前に、既にわかっていることをメモリで更新したいと思います。
ご覧のとおり、これらは2つの類似したアクションです。 書くとき
@my_decorator
-インタプリタに「
my_decoratorという関数を呼び出す」ように伝えます。 これは重要なポイントです。なぜなら、この名前はどちらもデコレーターに直接つながる可能性があるからです。
怖いことをしましょう!:)
def decorator_maker(): print " ! : "+\ " ." def my_decorator(func): print " - ! : ." def wrapped(): print (" - . " " . " " .") return func() print " ." return wrapped print " ." return my_decorator
長い? 長い。 中間変数を使用せずにこのコードを書き直します。
def decorated_function(): print " - ." decorated_function = decorator_maker()(decorated_function)
そして今、再び、さらに短く:
@decorator_maker() def decorated_function(): print "I am the decorated function." # : # ! : . # . # - ! : . # . # : decorated_function() # : # - . . # . # - .
「@」記号の後に関数を呼び出したことに気づきましたか?:)
最後に、デコレータの引数に戻りましょう。関数を使用してその場でデコレータを作成すれば、引数を渡すことができますよね?
def decorator_maker_with_arguments(decorator_arg1, decorator_arg2): print " ! :", decorator_arg1, decorator_arg2 def my_decorator(func): print " - . :", decorator_arg1, decorator_arg2
*-注 翻訳者:この例では、著者は人気シリーズThe Big Bang Theoryの主人公の名前に言及しています。ここに、任意の引数を渡すことができる人気のデコレータがあります。
もちろん、変数は引数にすることができます。
c1 = "" c2 = "" @decorator_maker_with_arguments("", c1) def decorated_function_with_arguments(function_arg1, function_arg2): print (" - : {0}" " {1}".format(function_arg1, function_arg2)) decorated_function_with_arguments(c2, "")
したがって、通常の関数のように、デコレータに引数を渡すことができます。 必要に応じて、
* argsおよび
** kwargsを使用してアンパックを使用できます。
ただし、デコレータは
1回だけ呼び出されることに注意してください。 Pythonがスクリプトをインポートした瞬間。 その後、引数whichを変更できなくなります。
「
import x 」と記述すると、
xからのすべての関数
が すぐに
装飾され 、何も変更できなくなります。
少し練習:デコレータをデコレータで書く
あなたがこの時点まで読んで、まだランクにいる場合-ここに私からのボーナスがあります。
この小さなトリックにより、通常のデコレータを引数を取るデコレータに変えることができます。
最初に、引数を取るデコレータを取得するために、別の関数を使用して作成しました。
デコレータを包みました。
関数をラップするものはありますか?
まさに、デコレーター!
デコレータ用のデコレータを作成して楽しみましょう。
def decorator_with_args(decorator_to_enhance): """ . , . . , , , , . """
これは次のように使用できます。
今のあなたの気持ちを知っていると思います。
あなたがこの感覚を最後に経験したとき、彼らがあなたに言っていることを聞いて:「再帰を理解するには、まず再帰を理解しなければなりません。」
しかし今、あなたはあなたがそれを理解したことをうれしく思いますか?;)
デコレータの使用に関する推奨事項
- デコレータはPython 2.4で導入されたので、コードの実行対象を確認してください。
- デコレータは、関数呼び出しを多少遅くします。忘れないでください。
- 関数を「デコード」することはできません。 もちろん、関数から切り離すことができるデコレータを作成するコツがありますが、これは悪い習慣です。 関数が装飾されている場合、元に戻すことはできません。
- デコレータは関数をラップするため、デバッグが難しくなります。
最後の問題は、Python 2.5で
functools.wrapsを含む
functoolsモジュールを標準ライブラリに追加することで部分的に解決されました。これにより、ラップされる関数に関するすべての情報(名前、モジュール領域、docstringsなど)がラッパー関数にコピーされます。
楽しい事実は、
functools.wraps自体がデコレータであることです。
デコレータはどのように使用できますか?
結論として、よく耳にする質問に答えたいと思います。なぜデコレータが必要なのですか? どのように使用できますか?
デコレータを使用して、サードパーティライブラリの関数の機能を拡張したり(変更できないコード)、デバッグを簡素化したりできます(まだ確立されていないコードを変更したくない)。
また、デコレータを使用して、同じコードを使用してさまざまな機能を拡張することも、毎回書き換えることなく便利です。たとえば、
def benchmark(func): """ , , . """ import time def wrapper(*args, **kwargs): t = time.clock() res = func(*args, **kwargs) print func.__name__, time.clock() - t return res return wrapper def logging(func): """ , . (, , !) """ def wrapper(*args, **kwargs): res = func(*args, **kwargs) print func.__name__, args, kwargs return res return wrapper def counter(func): """ , . """ def wrapper(*args, **kwargs): wrapper.count += 1 res = func(*args, **kwargs) print "{0} : {1}x".format(func.__name__, wrapper.count) return res wrapper.count = 0 return wrapper @benchmark @logging @counter def reverse_string(string): return str(reversed(string)) print reverse_string(" ") print reverse_string("A man, a plan, a canoe, pasta, heros, rajahs, a coloratura, maps, snipe, percale, macaroni, a gag, a banana bag, a tan, a tag, a banana bag again (or a camel), a crepe, pins, Spam, a rut, a Rolo, cash, a jar, sore hats, a peon, a canal: Panama!")
したがって、デコレータは任意の関数に適用でき、その機能を拡張し、1行のコードを書き直す必要はありません!
import httplib @benchmark @logging @counter def get_random_futurama_quote(): conn = httplib.HTTPConnection("slashdot.org:80") conn.request("HEAD", "/index.html") for key, value in conn.getresponse().getheaders(): if key.startswith("xb") or key.startswith("xf"): return value return ", ... !" print get_random_futurama_quote() print get_random_futurama_quote()
Pythonには、
property、staticmethodなどのデコレーターが含まれています。
Djangoでは、デコレータを使用して、キャッシュの制御、権限の制御、アドレスハンドラの定義を行います。 Twistedでは、偽の非同期インライン呼び出しを作成します。
デコレータは、実験のための最も広い範囲を開きます! そして、この記事がその開発に役立つことを願っています!
ご清聴ありがとうございました!
内容:
ご注意 翻訳者:
翻訳とデザインに関するコメントに感謝します。 記事の2番目の部分が、最初の部分よりも自明で有用なものになっていることを願っています。