入門python装飾器への理解

9552 ワード

デコレーション
これは个人の学习の笔记で、内容はただ参考に供して、転載して作者を明记してください、もし间违いがあれば、指摘を歓迎します.)
以前ここまで学んだことを覚えていて、python装飾器についての文章をたくさん見て、装飾器についてまだ半解で、それからいくつかの例の中で、最も素朴な方法でやっと装飾器とは何かを明らかにしましたか?以下は個人の装飾器に対するメモです.
装飾器とは何ですか.
装飾器を学ぶ前に、装飾器が何なのかを明らかにしなければなりません.文字で説明すると、装飾器は実際に関数を追加したり、プログラムに機能を追加したりするためです.また、この関数やプログラムが引用されていることを考慮すると、関数やプログラム自体を修正することはできないので、装飾器があり、斧を持って木を切る能力を持っていることが想像できます.これが装飾器の役割です.
装飾器は以下の2点を満たす必要があります.
  • 元のプログラムまたは関数のコードを変更しない
  • 関数またはプログラムの呼び出し方法を変更しない
  • ps:ここで理解しなければ、人で木を切る例もあります.例えば、明ちゃんは彼が個人で、あなたは彼に木を切らせて、彼はどのように切って、彼に木を切る能力を持っていなければならなくて、それでは問題が来て、どのように彼にこの能力を持っていますか?はい、彼に薬剤を注射して、彼を強くすることができますが、これは上記の第一点を満たしていません.改造された明ちゃんは私たちは彼を知らないので、どのように彼を木を切るか分かりません.だから、前提条件が必要です.1、ソースコードを修正してはいけません.2つ目は、呼び出し方法を変更しないことです.もともと私を明ちゃんに木を切りに行かせたいと思って明ちゃんに命令しました.「ねえ明ちゃんは木を切りに行きなさい」と言っていましたが、明ちゃんはできません.どうすればいいですか.会の人に明ちゃんを連れて行かせます.この過程は何になりましたか.あなたはある人に明ちゃんを連れて行かせて、あなたが明ちゃんを行かせるのではなく、呼び出し方法の変化が現れました.
    インスタンスでの理解
    第一歩:装飾器の前奏
    テストの関数を定義し、入力した値を返します.
    def test1(a):
    	return a
    

    上記で定義した関数は、入力値を返す役割を果たします.次に、自身の実行時間を計算する機能を追加することを考慮します.最も簡単な考え方は、記録開始時間->実行関数->記録終了時間、終了時間から開始時間を減算することです.以下のようにします.
    import time
    start_time = time.time()	#     
    test1(250)					#       
    stop_time = time.time()		#     
    delta_time = stop_time - start_time    #     ,     
    

    さあ、簡単に実現しました.必要に応じてこのプロシージャを関数にカプセル化し,呼び出し1回でtest 1の実行時間を返す.関数に詰めると、次のようになります.
    def test2()
    	start_time = time.time()	#     
    	test1(250)					#       
    	stop_time = time.time()		#     
    	delta_time = stop_time - start_time    #     ,     
    	print('{:f}'.format(delta_time))  	   #      
    

    実行してください
    >>> test2(250)
    '0.000001'
    

    ここでは、上記の手順をtest 2にカプセル化した後、test 2を呼び出すことでtest 1関数の実行時間を得ることができるが、(1)呼び出し方法を変更し、装飾器の説明に従ってtest 1を直接呼び出すべきである(2)ここではtest 1(250)のみが検討されている点、すなわち、このときtest 1には固定パラメータが1つしかない点、これにより、パラメータによって実行時間が異なるかどうかは保証されません.
    この2つの点についてさらに改善する
    まず、呼び出しについて固定パラメータではなく、以下のように解決します.
    def test2(func):
    	def test3(x):
    		start_time = time.time()	#     
    		func(x)						#       	
    		stop_time = time.time()		#     
    		delta_time = stop_time - start_time    #     ,     
    		return '{:f}'.format(delta_time)  	   # f       
    	return test3
    
    def test1(a):
    	return a
    

    実行してください
    >>> test2(test3)(250)
    '0.000002'
    

    現在、test 1、test 2、test 3の3つの関数があります.プロセス全体がtest 1の実行時間を計算するために整理されているのか、「記録開始時間->実行関数->記録終了時間」というプロセスなのか.
    上記のコードでは、まずtest 1の関数アドレスをパラメータとしてtest 2に入力したが、このときtest 2(func)はtest 2(test 1)に相当し、test 2では、もう1つのtest 3を定義する.上記の実行時間を求める流れを入れると、test 3にfunc(x)が見えます.funcは私たちが入力したアドレスであるtest 1です.test 1の実行時間を計算するには、必ず呼び出す必要があります.func()はfuncの呼び出しで、func(x)はtest 1(x)に相当します.
    さらにtest 2関数の戻り値を見ると、test 3のアドレスであり、呼び出しによってエラーが報告されることはなく、test 3関数のアドレスを持っているだけである.一方でtest 3を取得して後の展開を保証するためである.今では目的がはっきりしている.test 2を呼び出すと、test 1のアドレスが入力され、またtest 3のアドレスが返されるため、実際には1回の操作を経て、test 2(test 1)はtest 3のアドレスのように、test 2(test 1)()はtest 3をインスタンス化した、すなわちtest 3()であり、xは最初に入力された250であることが明らかになる.このようにして、様々なパラメータにおけるtest 1の実行時間を得ることができるようになった.
    第2ステップ、装飾器の実現
    さっき2つの点について話しましたが、もう1つ解決して、呼び出し方法を解決します.test 1関数に@test 2を追加します.これは文法糖で、効果は以下の通りです.
    def test2(func):
    	def test3(x):
    		start_time = time.time()	#     
    		func(x)						#       	
    		stop_time = time.time()		#     
    		delta_time = stop_time - start_time    #     ,     
    		return '{:f}'.format(delta_time)  	   # f       
    	return test3
    
    @test2
    def test1(a):
    	return a
    

    実行してください
    >>> test1(250)
    '0.000001'
    

    文法糖を加えてtest 1を直接呼び出すと所望の結果が得られた.では、この文法糖の役割は明らかです.test 2(test 1)に代わるものです.
    すなわちtest 2(test 1)(250)は直接文法糖によってtest 1(250)に省略されているが,両者は同じ効果であるが,呼び出し方法を変更しないことを満たし,test 1のソースコードを最初から最後まで修正したことがない.
    これが飾りです.(2018.11.16)