python黒魔法---装飾器(decorator)
5509 ワード
pythonは優雅な言語で、魔法のような使い方もあります.装飾器(decorator)は腐敗性を不思議にする技術である.最近はずっとTornadoフレームを使っていて、ずっとFlaskを忘れませんでした.Flaskは私の大好きなPythonフレームワークで、最初に惹かれたのも装飾器という文法糖(Syntactic sugar)を使ってRouterを作って、コードを甘く見せるからです.
Tornadoの中のRouterは少し平板で、Flaskの味が懐かしくて、Flaskがどのようにこの魔法を使うか知りたいです.Flaskのソースコードを読むことで、Tornadoのために装飾器Routerを実現することもできます.
もちろんPythonに触れたばかりの人は、装飾器の本質がデザインモードの装飾器モードであることを理解しやすいかもしれません.しかしPythonは
すべてが対象
Pythonではすべてが対象で、もちろんすべてが彼女であるわけではありません.関数もオブジェクトなので、パラメータとして渡すことができます.たとえば、次のようにします.
私たちのgreet関数のパラメータは、関数オブジェクトでもあります.このパラメータオブジェクトを渡すことができます.greetを呼び出すとgreet内部で関数パラメータの呼び出しが行われます.
装飾モード
装飾モードは、その名の通り、ターゲット関数を呼び出す前に、この関数オブジェクトを装飾します.たとえば、データベースを操作する方法です.データをクエリーする前に、データベースに接続する必要があります.クエリーが終了したら、接続を切断して閉じる必要があります.通常の論理は次のとおりです.
接続データベース(connect_db)と閉じた接続(close_db)を関数にカプセル化しました.query_Dataメソッドは、クエリの具体的な論理を実行します.このように異なるクエリー方法が必要で、クエリーの論理も一つの方法にカプセル化するだけでOkla
クエリーの関数オブジェクトを転送し、冒頭の説明に合致するすべてがオブジェクトです.アクセサリーが完成しました.はい、簡単です.query_dataはquery_userの装飾はもちろんquery_も書けますblogなどの方法.
など、装飾関数を使用する前に、プロジェクトのコードに大量のquery_がある場合を想定します.userメソッドの呼び出し.query_を使用した場合data包装.前のqueryをuser()の場所はすべてquery_に置き換えられますdata(query_user).コードの変更を減らすにはどうすればいいですか?
私たちの出発点は前のqueryを維持するためです.user()は変更されず、実際にはquery_が呼び出されます.data(query_user).もしquery_dataが呼び出されると、関数が返されますか?たとえば、次のコードがあります.
これで完全な装飾器が完成し、前のバージョンよりも前に書いたqueryを変更する必要はありません.userコード.キーはquery_ですdata呼び出しのとき、wrapper関数が返され、このwrapper関数はquery関数呼び出しの前後のいくつかの論理を実行します.もう一つのポイントはアクセサリーquery_を呼び出すことですdata装飾関数.
文法糖@
前のコードでは、pythonのアクセサリー構文糖@を使用できます.以下のようにします.
前の装飾器が装飾を呼び出すとpythonに文法糖があります.装飾関数の前に
に等しい
被装飾関数パラメータ
私たちが装飾された関数は、パラメータを持つことが多いので、装飾器を通じてどのようにパラメータを伝達しますか?回想すると,装飾器関数は装飾された関数に対して装飾され,wrapper関数を返すのが用いられる.実はこの関数は装飾された関数に等しいが、wrapperはもっと多くのことをしただけだ.装飾された関数パラメータはwrapperによって伝達できる.次のようになります.
これにより,装飾された関数伝達パラメータが実現される.もちろん、位置パラメータもキーワードパラメータも可変パラメータも可能です.
装飾パラメータ
flaskでは、ビュー関数の装飾は、装飾器にurl正則を伝達する、すなわち、装飾器にパラメータを伝達する、被装飾器のパラメータとは異なる.
私たちはどのようにrouterという装飾器を定義しますか?実は元の装飾器の外にもう1階包むだけで、つまり装飾器に対して装飾を行います.
@router()この文法糖は迷っているように見えますが、実はよく理解しています.ここでは、2つのステップの最初のステップがrouterという関数を呼び出すことと見なすことができます.
ステップ2では、装飾を行います.
つながった効果は
今思えば、
もちろん、装飾器を使用するのは、前述したflaskのrouterのような包装が必要な方法を実現するためです.
素晴らしいTutorial:Things which aren't magic-Flask and@appを書いた人がいます.routeは、装飾の確定理解を深めることを参考にすることができ、装飾器には多くの用途がある.
Enjoy~
Tornadoの中のRouterは少し平板で、Flaskの味が懐かしくて、Flaskがどのようにこの魔法を使うか知りたいです.Flaskのソースコードを読むことで、Tornadoのために装飾器Routerを実現することもできます.
もちろんPythonに触れたばかりの人は、装飾器の本質がデザインモードの装飾器モードであることを理解しやすいかもしれません.しかしPythonは
@
個を通じて装飾器の文法糖を実現した.本文の目的は@を神秘的にしないことです.すべてが対象
Pythonではすべてが対象で、もちろんすべてが彼女であるわけではありません.関数もオブジェクトなので、パラメータとして渡すことができます.たとえば、次のようにします.
def say_english():
print 'hello'
def say_chinese():
print ' '
say_english() # hello
say_chinese() #
def greet(say):
say()
greet(say_english) # hello
greet(say_chinese) #
私たちのgreet関数のパラメータは、関数オブジェクトでもあります.このパラメータオブジェクトを渡すことができます.greetを呼び出すとgreet内部で関数パラメータの呼び出しが行われます.
装飾モード
装飾モードは、その名の通り、ターゲット関数を呼び出す前に、この関数オブジェクトを装飾します.たとえば、データベースを操作する方法です.データをクエリーする前に、データベースに接続する必要があります.クエリーが終了したら、接続を切断して閉じる必要があります.通常の論理は次のとおりです.
def connect_db():
print 'connect db'
def close_db():
print 'close db'
def query_user():
connect_db()
print 'query the user'
close_db()
query_user() # connect db
# query the user
# close db
接続データベース(connect_db)と閉じた接続(close_db)を関数にカプセル化しました.query_Dataメソッドは、クエリの具体的な論理を実行します.このように異なるクエリー方法が必要で、クエリーの論理も一つの方法にカプセル化するだけでOkla
def query_user():
print 'query some user'
def query_data(query):
connect_db()
query()
close_db()
query_data(query_user)
クエリーの関数オブジェクトを転送し、冒頭の説明に合致するすべてがオブジェクトです.アクセサリーが完成しました.はい、簡単です.query_dataはquery_userの装飾はもちろんquery_も書けますblogなどの方法.
など、装飾関数を使用する前に、プロジェクトのコードに大量のquery_がある場合を想定します.userメソッドの呼び出し.query_を使用した場合data包装.前のqueryをuser()の場所はすべてquery_に置き換えられますdata(query_user).コードの変更を減らすにはどうすればいいですか?
私たちの出発点は前のqueryを維持するためです.user()は変更されず、実際にはquery_が呼び出されます.data(query_user).もしquery_dataが呼び出されると、関数が返されますか?たとえば、次のコードがあります.
def query_user():
print 'query some user'
def query_data(query):
""" , , query wrapper """
def wrapper():
connect_db()
query()
close_db()
return wrapper
# query_data ( )
query_user = query_data(query_user)
# query_user
query_user()
これで完全な装飾器が完成し、前のバージョンよりも前に書いたqueryを変更する必要はありません.userコード.キーはquery_ですdata呼び出しのとき、wrapper関数が返され、このwrapper関数はquery関数呼び出しの前後のいくつかの論理を実行します.もう一つのポイントはアクセサリーquery_を呼び出すことですdata装飾関数.
文法糖@
前のコードでは、pythonのアクセサリー構文糖@を使用できます.以下のようにします.
def query_data(query):
def wrapper():
connect_db()
query()
close_db()
return wrapper
# @
@query_data
def query_user():
print 'query some user'
query_user()
前の装飾器が装飾を呼び出すとpythonに文法糖があります.装飾関数の前に
@
を追加すると、@query_data
がquery_data()
に等しいいくつかの装飾関数を呼び出すと理解できる.実際には、このように使用するのではなく、このような全体です.@query_data
def query_user():
print 'query some user'
に等しい
query_user = query_data(query_user)
被装飾関数パラメータ
私たちが装飾された関数は、パラメータを持つことが多いので、装飾器を通じてどのようにパラメータを伝達しますか?回想すると,装飾器関数は装飾された関数に対して装飾され,wrapper関数を返すのが用いられる.実はこの関数は装飾された関数に等しいが、wrapperはもっと多くのことをしただけだ.装飾された関数パラメータはwrapperによって伝達できる.次のようになります.
def query_data(query):
def wrapper(count):
connect_db()
query(count)
close_db()
return wrapper
@query_data
def query_user(count):
print 'query some user limit {count}'.format(count=count)
query_user(count=100) # connect db
# query some user limit 100
# close db
これにより,装飾された関数伝達パラメータが実現される.もちろん、位置パラメータもキーワードパラメータも可変パラメータも可能です.
装飾パラメータ
flaskでは、ビュー関数の装飾は、装飾器にurl正則を伝達する、すなわち、装飾器にパラメータを伝達する、被装飾器のパラメータとは異なる.
@app.router('/user')
def user_page():
return 'user page'
私たちはどのようにrouterという装飾器を定義しますか?実は元の装飾器の外にもう1階包むだけで、つまり装飾器に対して装飾を行います.
def router(url):
print 'router invoke url', url
def query_data(query):
print 'query_data invoke url', url
def wrapper(count):
connect_db()
query(count)
close_db()
return wrapper
return query_data
@router('/user') # router , router invoke url /user, @ , 'query_data invoke url', url
def query_user(count):
print 'query some user limit {count}'.format(count=count)
query_user(count=100) # connect db
# query some user limit 100
# close db
@router()この文法糖は迷っているように見えますが、実はよく理解しています.ここでは、2つのステップの最初のステップがrouterという関数を呼び出すことと見なすことができます.
query_data = router('/user')
ステップ2では、装飾を行います.
@query_data
def query_user():
pass
つながった効果は
query_user = query_data(query_user))
query_user = router("/user")(query_user))
今思えば、
@
という文法糖は甘いでしょう.そしてpythonと同じようによく理解され、よく使われています.もちろん、装飾器を使用するのは、前述したflaskのrouterのような包装が必要な方法を実現するためです.
素晴らしいTutorial:Things which aren't magic-Flask and@appを書いた人がいます.routeは、装飾の確定理解を深めることを参考にすることができ、装飾器には多くの用途がある.
Enjoy~