前の記事では、要件の問題を解決することでクロージャについて学習しましたが、この記事では、要件をゆっくりと進化させ、Python デコレータを段階的に理解することで、同じことを行います。
まず、従業員の出勤情報を出力する関数があります:
def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
出力結果は次のとおりです:
昵称:两点水 部门:做鸭事业部 上班打卡成功
次に、製品フィードバック、いいえ, 職場での打刻方法に関する具体的な情報はありません。日付と、チェックインの特定の日付を加えれば、これは非常に簡単で数分で解決できるはずです。次に、日付を出力するコードを次のように追加します。
import time def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
出力結果は次のとおりです。
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
このように変更しても問題ありませんが、関数の機能構造。この関数が定義されたときは、従業員に関する情報を出力し、チェックインが成功したことを通知するためのものでした。現在、日付を出力するコードを追加すると、多くのコード重複の問題が発生する可能性があります。たとえば、従業員情報を出力して正常に入力するだけでよいが、日付は必要ない別の場所があります。その場合、関数を書き直す必要がありますか?さらに、現在の日付を出力するこの関数メソッドは頻繁に使用され、各モジュール メソッドのパブリック関数として呼び出すことができます。もちろん、これらはすべてプロジェクト全体として考慮されます。
この場合、関数型プログラミングを使用してコードのこの部分を変更できます。これまでの学習により、Python 関数には 2 つの特徴があることがわかっています。関数はオブジェクトでもあり、関数は関数内にネストすることができます。次に、コードを次のように変更します:
import time def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() add_time(punch)
出力結果:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
この方法ではパンチ メソッドは変更されず、現在の日付を出力する必要がある関数は次のように関数を add_time に渡すだけで済むことがわかりました:
import time def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') def add_time(func): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() def holiday(): print('天气太冷,今天放假') add_time(punch) add_time(holiday)
結果の出力:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功 2018-01-09 天气太冷,今天放假
関数プログラミングを使用するのは非常に便利ですか? ただし、関数を呼び出すたびに、元の関数をパラメーターとして渡す必要があります。それを実装するより良い方法はありますか? ?はい、この記事で紹介するデコレータです、デコレータの書き方は実際にはクロージャと似ていますが、自由変数がないので、上記のコードでデコレータを書く方法を示します。プログラミングと関数型プログラミングの違いは何ですか?
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') f = decorator(punch) f()
出力結果:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
コードを通して、デコレーター関数が通常次の 3 つのことを実行することがわかります:
関数をパラメーターとして受け取る
ラッパー関数をネストすると、ラッパー関数は元の関数と同じパラメーターを受け取り、元の関数を実行し、追加の関数も実行します
ネストされた関数に戻る
ただし、次のようになります。このコードをよく見てみると、このデコレータの書き方が関数型プログラミングよりも面倒なのはなぜでしょうか。そして、それは複雑で、少し不必要にさえ見えます。
これは、デコレーターの「構文糖」をまだ使用していないためです。上記のコードを見ると、Python がデコレーター (Decorator) を導入したときに、新しい構文機能が導入されていないことがわかります。すべては関数、文法的特徴に基づいています。これは、デコレータが Python に固有のものではなく、すべての言語に共通するプログラミングの考え方であることも示しています。 Python が @ 構文シュガーを設計しただけで、デコレータを定義し、そのデコレータを元の関数として呼び出し、その結果を元の関数のオブジェクト名に代入するプロセスがよりシンプルで便利で操作しやすくなります。 Python デコレーターの構文糖衣であると言えます。
それでは、その構文シュガーをどのように使用するのでしょうか?とても簡単で、上記の書き方に従ってデコレータ関数を書いた後、元の関数に直接@とデコレータの関数名を追加します。次のように:
import time def decorator(func): def punch(): print(time.strftime('%Y-%m-%d', time.localtime(time.time()))) func() return punch @decorator def punch(): print('昵称:两点水 部门:做鸭事业部 上班打卡成功') punch()
出力結果:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功
これは呼び出しに非常に便利です。たとえば、この例では、デコレーターを使用した後、元のコードに直接追加するだけです。デコレーターの構文糖を関数に追加します。この関数には変更はなく、呼び出し場所を変更する必要はありません。
しかし、ここには常に問題があり、パンチイン情報の出力は固定されているため、パラメーターを介して渡す必要があるということです。デコレータの関数は *args 変数パラメータを使用できますが、 *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('两点水', '做鸭事业部') print_args('两点水', sex='男', age=99)
出力結果は次のようになります:
2018-01-09 昵称:两点水 部门:做鸭事业部 上班打卡成功 2018-01-09 两点水 {'sex': '男', 'age': 99}
この時点で、に関する一連の記事は次のようになります。草の根Python入門は終わりました。