ホームページ  >  記事  >  バックエンド開発  >  Python デコレータについての深い理解

Python デコレータについての深い理解

高洛峰
高洛峰オリジナル
2017-01-23 14:41:541054ブラウズ

デコレーターの紹介:

Decorator (デコレーター) は、高度な Python 構文です。デコレーターは関数、メソッド、またはクラスを処理できます。 Python では、関数やクラスを処理するさまざまな方法があります。たとえば、Python クロージャでは、関数オブジェクトを特定の関数の戻り結果として認識します。他のメソッドと比較して、デコレータの構文はシンプルであり、コードは非常に読みやすいです。したがって、デコレータは Python プロジェクトで広く使用されています。

Decorator は Python 2.5 で初めて登場しました。元々は、関数やメソッドなどの呼び出し可能なオブジェクトを処理するために使用されていました (このようなオブジェクトは __call__ メソッドで定義されます)。 Python 2.6 以降の Python バージョンでは、クラスの処理にデコレータがさらに使用されます。

デコレーターは主に、ログの出力、関数のタイミング、ID 認証など、一般的に使用される関数の関数をラップするために使用されます。これを実現するためにデコレータを使用すると、プログラム全体の複雑さを軽減し、プログラム内のコードの量を減らすことができます。

これは実際には関数です。違いは、関数をパラメータとして受け取り、関数の代替バージョンを返すことです。

以下の簡単な例を見てください:

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
def f(x):
return x
f=add_number(f)
print f(20)

add_number は、関数 (f) をパラメーターとして受け取り、元の関数に割り当てる別の関数 (adder) を返します。 、オリジナルのこの関数は、コードを追加せずに加算関数を実装します。

これはデコレーターのオリジナルの実装です。

しかし、この方法はまだ少し不便です。結局のところ、元の関数を再割り当てするために f=add_number(f) を使用します。

実際、次のメソッドを使用して、Python でのデコレータへの参照を簡素化できます。

def add_number(func):
def adder(arg):
return func(arg)+100
return adder
@add_number
def f(x):
return x
print f(20)

必要なのは単純な @add_numbe 呼び出しだけであり、非常に簡単で、基本的に元のコードに侵入することはありません。

さて、デコレーターとして毎回受け入れられるパラメータは関数と関数パラメータの 2 つだけですが、記述形式は基本的に同じであることに誰もが気づきました。この種の記述を簡略化する方法はありますか?

はい、Python にはデコレーターの作成を大幅に簡素化できるデコレーター パッケージが用意されています。

それで、3 番目の実装方法は次のとおりです:

from decorator import decorator
@decorator
def wrapper(func,arg):
return func(arg)+100
@wrapper
def f(x):
return x
print f(20)

ああ、それは本当に簡単です~

実際、上記の例はすべて 1 つのパラメーターを受け入れます。

例:

@decorator
def wrapper(f,arg1,*args,**kwargs):
print "I am just a wrapper~"
return f(arg1,*args,**kwargs)
@wrapper
def f(arg1,*args,**kwargs):
print arg1
for eacheArg in args:
print 'non-keyword arg:',eacheArg
for eachKw in kwargs.keys():
print 'keyword arg: %s:%d' % (eachKw,kwargs[eachKw])
args=('Joy','Steve')
kwargs={"age":20}
f('China',*args,**kwargs)

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

I am just a wrapper~
China
non-keyword arg: Joy
non-keyword arg: Steve
keyword arg: age:20

*args と **kwargs の違いについては、どちらも可変長パラメーターを表すために使用できます。前者は Yuanzu で表されキー値を持たないのに対し、後者はキー値を持つ辞書であるという点だけです。両方を同じ関数で使用できますが、*args は **kwargs の前に指定する必要があります。

次の例のように:

def test_var_args_call(arg1, arg2, arg3):
print "arg1:", arg1
print "arg2:", arg2
print "arg3:", arg3
args=(1,2,3)
kwargs ={"arg1":"1","arg3": 3, "arg2": "2"}
test_var_args_call(*args)
print '-----------------'
test_var_args_call(**kwargs)

どちらの実装効果も同じです。

最後の例は、関数の実行時間を表示することで関数を装飾することです

import time
def log(func):
def wrapper(*args, **kw):
print '[%s] %s() was called...' % (time.ctime(),func.__name__)
return func(*args, **kw)
return wrapper
@log
def foo():
pass
for i in range(4):
foo()
time.sleep(1)

出力結果は次のとおりです:

[Wed Jul 27 09:17:23 2016] foo() was called...
[Wed Jul 27 09:17:24 2016] foo() was called...
[Wed Jul 27 09:17:25 2016] foo() was called...
[Wed Jul 27 09:17:26 2016] foo() was called...

上記は、ご質問がございましたら、メッセージを残してください。編集者がすぐにご返答いたします。また、PHP 中国語 Web サイトをサポートしていただきありがとうございます。

Python デコレータ関連の記事をより深く理解するには、PHP 中国語 Web サイトに注目してください。

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