デコレータ
前の記事では、要件の問(wèn)題を解決することでクロージャについて學(xué)習(xí)しましたが、この記事では、要件をゆっくりと進(jìn)化させ、Python デコレータを段階的に理解することで、同じことを行います。
まず、従業(yè)員の出勤情報(bào)を出力する関數(shù)があります:
def punch(): print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') punch()
出力結(jié)果は次のとおりです:
昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功
次に、製品フィードバック、いいえ, 職場(chǎng)での打刻方法に関する具體的な情報(bào)はありません。日付と、チェックインの特定の日付を加えれば、これは非常に簡(jiǎn)単で數(shù)分で解決できるはずです。次に、日付を出力するコードを次のように追加します。
import time def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') punch()
出力結(jié)果は次のとおりです。
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功
このように変更しても問(wèn)題ありませんが、関數(shù)の機(jī)能構(gòu)造。この関數(shù)が定義されたときは、従業(yè)員に関する情報(bào)を出力し、チェックインが成功したことを通知するためのものでした?,F(xiàn)在、日付を出力するコードを追加すると、多くのコード重複の問(wèn)題が発生する可能性があります。たとえば、従業(yè)員情報(bào)を出力して正常に入力するだけでよいが、日付は必要ない別の場(chǎng)所があります。その場(chǎng)合、関數(shù)を書き直す必要がありますか?さらに、現(xiàn)在の日付を出力するこの関數(shù)メソッドは頻繁に使用され、各モジュール メソッドのパブリック関數(shù)として呼び出すことができます。もちろん、これらはすべてプロジェクト全體として考慮されます。
この場(chǎng)合、関數(shù)型プログラミングを使用してコードのこの部分を変更できます。これまでの學(xué)習(xí)により、Python 関數(shù)には 2 つの特徴があることがわかっています。関數(shù)はオブジェクトでもあり、関數(shù)は関數(shù)內(nèi)にネストすることができます。次に、コードを次のように変更します:
import time def punch(): print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() add_time(punch)
出力結(jié)果:
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功
この方法ではパンチ メソッドは変更されず、現(xiàn)在の日付を出力する必要がある関數(shù)は次のように関數(shù)を add_time に渡すだけで済むことがわかりました:
import time def punch(): print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() def holiday(): print('天氣太冷,今天放假') add_time(punch) add_time(holiday)
結(jié)果の出力:
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功 2018-01-09 天氣太冷,今天放假
関數(shù)プログラミングを使用するのは非常に便利ですか? ただし、関數(shù)を呼び出すたびに、元の関數(shù)をパラメーターとして渡す必要があります。それを?qū)g裝するより良い方法はありますか? ?はい、この記事で紹介するデコレータです、デコレータの書き方は実際にはクロージャと似ていますが、自由変數(shù)がないので、上記のコードでデコレータを書く方法を示します。プログラミングと関數(shù)型プログラミングの違いは何ですか?
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch def punch(): print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') f = decorator(punch) f()
出力結(jié)果:
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功
コードを通して、デコレーター関數(shù)が通常次の 3 つのことを?qū)g行することがわかります:
関數(shù)をパラメーターとして受け取る
ラッパー関數(shù)をネストすると、ラッパー関數(shù)は元の関數(shù)と同じパラメーターを受け取り、元の関數(shù)を?qū)g行し、追加の関數(shù)も実行します
ネストされた関數(shù)に戻る
ただし、次のようになります。このコードをよく見(jiàn)てみると、このデコレータの書き方が関數(shù)型プログラミングよりも面倒なのはなぜでしょうか。そして、それは複雑で、少し不必要にさえ見(jiàn)えます。
これは、デコレーターの「構(gòu)文糖」をまだ使用していないためです。上記のコードを見(jiàn)ると、Python がデコレーター (Decorator) を?qū)毪筏郡趣?、新しい?gòu)文機(jī)能が導(dǎo)入されていないことがわかります。すべては関數(shù)、文法的特徴に基づいています。これは、デコレータが Python に固有のものではなく、すべての言語(yǔ)に共通するプログラミングの考え方であることも示しています。 Python が @ 構(gòu)文シュガーを設(shè)計(jì)しただけで、デコレータを定義し、そのデコレータを元の関數(shù)として呼び出し、その結(jié)果を元の関數(shù)のオブジェクト名に代入するプロセスがよりシンプルで便利で操作しやすくなります。 Python デコレーターの構(gòu)文糖衣であると言えます。
それでは、その構(gòu)文シュガーをどのように使用するのでしょうか?とても簡(jiǎn)単で、上記の書き方に従ってデコレータ関數(shù)を書いた後、元の関數(shù)に直接@とデコレータの関數(shù)名を追加します。次のように:
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch @decorator def punch(): print('昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功') punch()
出力結(jié)果:
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功
これは呼び出しに非常に便利です。たとえば、この例では、デコレーターを使用した後、元のコードに直接追加するだけです。デコレーターの構(gòu)文糖を関數(shù)に追加します。この関數(shù)には変更はなく、呼び出し場(chǎng)所を変更する必要はありません。
しかし、ここには常に問(wèn)題があり、パンチイン情報(bào)の出力は固定されているため、パラメーターを介して渡す必要があるということです。デコレータの関數(shù)は *args 変數(shù)パラメータを使用できますが、 *args を使用するだけではすべてのパラメータを完全に含めることはできません。たとえば、キーワード パラメータは使用できません。キーワード パラメータと互換性を持たせるために、 **kwargs も追加する必要があります。
したがって、デコレータの最終形式は次のように記述できます:
import time def decorator(func): def punch(*args, **kwargs): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func(*args, **kwargs) return punch @decorator def punch(name, department): print('昵稱:{0} 部門:{1} 上班打卡成功'.format(name, department)) @decorator def print_args(reason, **kwargs): print(reason) print(kwargs) punch('兩點(diǎn)水', '做鴨事業(yè)部') print_args('兩點(diǎn)水', sex='男', age=99)
出力結(jié)果は次のようになります:
2018-01-09 昵稱:兩點(diǎn)水 部門:做鴨事業(yè)部 上班打卡成功 2018-01-09 兩點(diǎn)水 {'sex': '男', 'age': 99}
この時(shí)點(diǎn)で、に関する一連の記事は次のようになります。草の根Python入門は終わりました。