-
フォローアップの説明では、デコレータの習熟が非常に要求されるため、この記事で詳しく説明します。コラム「Python フルスタック シリーズ チュートリアル」を読んだ友人は、デコレータが既に記事を公開していると言うかもしれません。もしそうなら、デコレータを深く勉強した友人がもう一度それを見直してください。同時に、この記事は拡張されます~
-
先に進む前に、関数とクロージャの概念をある程度理解していることを確認してください。これらはデコレータを理解するための基本です。詳細は「20.Python関数(5)【関数プログラミング前半】」、「21.Python関数(6)【関数プログラミング後半】」を参照してください。
Python - デコレータの詳細
3 つの質問:
- デコレータとは何ですか?
- 手書きのデコレーター?
- デコレーターはどこで使用されたり、見られたりしましたか?
1. デコレータとは何ですか?
あるいは、なぜデコレータを使用するのでしょうか?
- Python では、デコレータは既存のオブジェクトに機能を追加する特別な構文です。デコレータは本質的に、他の関数またはクラスをパラメータまたは戻り値として受け取ることができる Python 関数またはクラスです。デコレーターの役割は、装飾されるオブジェクトのソース コードを変更せずに機能を追加することです。
デコレータを使用する利点:
-
コードの再利用: コードの冗長性を避けるために、デコレータを複数の関数またはクラス間で再利用できます。
-
関数の動的な追加: デコレーターを通じて、新しい関数をオブジェクトに動的に追加したり、既存の関数を実行時に変更したりできます。たとえば、Flask では、認証やルート登録など、多くの一般的な機能がデコレータを通じて実装されます。
-
コード構造を簡素化する: デコレーターは、一部の一般的なコード ロジックを抽象化し、各関数で同じコードを記述することを回避できます。これにより、コード構造がより明確になり、保守が容易になります。
-
コードの可読性の向上: デコレーターは、ソース コードから余分なロジックとコードを分離し、ソース コードをより簡潔で理解しやすくします。
-
コードの分離: デコレーターを通じて、さまざまなロジックを分離して、コード間の結合を減らすことができます。
- つまり、デコレータは Python の非常に強力で柔軟な機能であり、コード構造を簡素化し、コードの可読性と保守性を向上させ、ソース コードを変更せずにコードに新しい関数を動的に追加できます。このため、デコレータは Python で非常に人気があり、広く使用されています。
2. 手書きのデコレータ?
- 基本的な関数は次のとおりです。
def index(a1):
return a1 + 1000
# 执行函数
v = index(2)
print(v)
# 获取函数名
print(index.__name__)
- 手書きのデコレータ:
# 装饰器
def wapper(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
- デコレータを使用します。
"""
@语法糖的作用:
1.看见@wrapper,执行wapper函数,并将被装饰的函数当做参数传递进去,即 wapper(index)
2.将第一步的返回值,重新赋值给 新index = wapper(老index)
"""
# 使用
@wapper
def index(a1):
return a1 + 1000
v = index(999)
print(v)
print(index.__name__) # 这里输出就不是index而是inner了,说明了上述说的第二步,即函数被重新赋值了
- 次のような疑問が生じます。
@wapper
def index(a1):
return a1 + 1000
@wapper
def order(a1):
return a1 + 1000
# 下面输出都是inner
print(index.__name__)
print(order.__name__)
-
トリガーの要件 - 関数が装飾されている場合でも、
__name__
元の関数の名前を取得したいですか? -
回避策 - デコレータで組み込みを使用します
functools.wraps()
。
import functools
def wapper(func):
@functools.wraps(func)
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
# 将装饰器改成这样之后,上面那俩输出一个是index,一个是order
functools.wraps() デコレータの実装原則:
- まず、各関数は独自のメタ情報(関数名/コメントなど)を持っており、functools.wraps()デコレータは元の関数(func)のメタ情報を関数(inner)に代入します。
3. デコレータはどこで使用されたり、見られたりしましたか?
このコラムに書くということは、言うまでもなくFlaskではデコレータが使われているということです。実は以前、ルートを登録するときに毎回デコレータを使っていませんか?
- Flask でのカスタム デコレータの使用を直接見てみましょう。
from flask import Flask
from functools import wraps
app = Flask(__name__)
def wapper(func):
@wraps(func)
def inner(args, **kwargs):
print('before')
return func(args, **kwargs)
return inner
@app.route('/xxx')
@wapper
def index():
return 'Index'
@app.route('/aaa')
@wapper
def order():
return 'Order'
if __name__ == '__main__':
app.run()
注意点:
- リクエストが届くたびにデコレーターが確実に実行されるようにするには、追加されたデコレーターがルートの下にある必要があります。
- エンドポイントのデフォルトは関数名であり、同じ名前を持つことはできません (エラーが報告されます)。そのため、functools のラップ デコレータを使用する必要があります。
デコレーター - 上級:
以下はインターネットから抜粋したコードです。この出力順序がなぜなのか理解できるかどうかを確認してください (メモが含まれています):
コメント エリアに思考の痕跡を残してください~
[あといくつかの記事で詳しく説明します。デコレータをチェックしてください。お楽しみに~]
def wrapper1(func): # func == f函数名 #哪个糖靠近被装饰函数,哪个语法糖函数就先执行,但是内部的inner却后执行
print('进入wrapper1了')
def inner1():
print('inner1') # 2
func() # 这个函数func是被装饰的函数
print('func1') # 4
return inner1 # @wrapper1最后一句f==inner1和@wrapper2后第一句f=wrapper2(f),变量替换,inner1 = wrapper2(f),这样就执行下面的装饰器函数了
def wrapper2(func): # func == inner1 上面返回一个inner1 = wrapper2(f)
print('进入wrapper2了')
def inner2():
print('inner2') # 1
func() # 这里的func()其实是inner1(),到上面去了
print('func2') # 5
return inner2
@wrapper2 # f = wrapper2(f) 里面的f==inner1 外面的f == inner2
@wrapper1 # f = wrapper1(f) 里面的f==函数名f 外面的f == inner1
def f(): # 3
print('主函数')
f() # inner2()