Python学習難点の装飾器

19256 ワード

知識の補完
ふていちょうパラメータ
def test(*args, **kwargs):
	print(args)
	print(kwargs)
test(3,'k',a=4,b='w')
#(3, 'k') args   (     )
#{'a': 4, 'b': 'w'} kwargs   (    )

アクティブドメイン
pythonでは、役割ドメインはグローバル役割ドメインとローカル役割ドメインの2つに分けられます.グローバル役割ドメインは、ファイルレベルで定義された変数、関数名です.ローカル役割ドメインは、関数の内部を定義します.
  • グローバル役割ドメインではローカル変数
  • にアクセスできません.
  • は、ローカル役割ドメインにおいてグローバル変数にアクセスできるが、グローバル変数を変更することはできない(もちろん修正する方法がある)
  • .
    pyhton関数の理解
    関数名は、メモリ領域のアドレスを指します.関数はpythonのオブジェクト(万物すべてのオブジェクト)です.
    高次関数
    関数名は、パラメータとして関数名を入力または返します.
    高次関数
    受信パラメータ
    さぎょう
    map
    1つの関数f、1つまたは複数のシーケンス
    fシーケンス内の各要素にそれぞれ作用し、新しいシーケンスを返す
    reduce
    1つの関数f、1つのシーケンス
    fは2つのパラメータを受信し、シーケンス内の2つの要素ごとにfを繰り返し呼び出す必要がある.
    filter
    1つの関数f、1つのシーケンス
    fはTrueまたはFalseを返し、fはlistの各要素をフィルタし、新しいシーケンスを返します.
    sorted
    1つのシーケンス、1つの関数f
    f 2つのパラメータサイズを判断し、カスタムソート後のシーケンスを返す
    匿名関数
    構文:lambda x:xx x:パラメータ;xx:式
    クローズドパッケージ関数
    関数を返す:関数名がパラメータとして返されます.遅延実行g()
    def f():
    	print('call f()')
    	def g():
    		print('call g()')
    	return g
    x = f() #call f()     f  ,g     
    x       # x            
    x()		#call g()	  g(), g()  x()
    

    ≪閉包関数|Closed Function|oem_src≫:内層関数は、外層関数の変数(非グローバル変数)を参照し、内層関数を返します.内層関数(戻り関数)は、次のiのような後続の変化する変数を参照しないでください.外部作用ドメインの局所変数も変更しない(例えば、f関数でiの値を変更しない)
    def count():
        fs = []
        for i in range(1, 4):
        	def f():
        		return i*i
        	fs.append(f) # f         ,i      
        return fs		#fs   [.f at 0x0000024496273488>,
        				#.f at 0x0000024496273510>,
        				#.f at 0x0000024496273598>]
    f1,f2,f3 = count()
    f1()	#9
    f2()	#9
    f3()	#9
    

    f関数をdef(j=i):j*jに変更すると、結果は1,4,9となります.jは局所変数であり,当時iのコピーとしてパラメータ後値が固定されている.
    組み込み関数:
    関数名
    パラメータ
    さぎょう
    slice(start,stop[,step])
    start:開始;stop:終了;[step:ステップ長]
    スライスオブジェクトを返します
    enumerate(sequence,[start=0])
    sequence:シーケンス/反復/反復をサポートするオブジェクト;start:下付き開始位置
    enumerateオブジェクトを返す
    zip([iterable,…])
    1つ以上の反復器
    各反復器の対応する位置の要素を取り出し、新しいメタグループを構成します.メタグループのリストを返します
    eval(expression[globals,locals])
    文字列式
    式の結果を返す
    デコレーション
    デザイナは呼び出し可能な関数で、呼び出し可能な関数を受け入れ、呼び出し可能な関数を返します.ただし、異なるタイプの呼び出し可能な関数を返すことができます.既存のモディファイヤは、元の関数の拡張関数、クラスを返すことができます.呼び出し可能な関数とは、任意の実装を意味します.call__メソッドの呼び出し可能なオブジェクト.アクセラレータは、他の関数またはクラスにコードの変更を必要とせずに追加機能を追加させることができ、アクセラレータの戻り値も関数/クラスオブジェクト(呼び出し可能)です.パラメータを伝達できる装飾器の例を以下に示します.
    import functools
    import json
    
    class JSONOutputError(Exception):
    	def __init__(self, message):
    		self._message = message
    	def __str__(self):
    		return self._message
    		
    def json_output(indent=None, sort_keys=False):
    	print('json_output called')
    	def actual_decorator(decorated):  #actual_decorator         
    		@functools.wraps(decorated) #    do_nothing           inner
    		def inner(*args, **kwargs): #        do_nothing      
    			print(args)
    			print(kwargs)
    			try:
    				result = decorated(*args, **kwargs)
    			except JSONOutputError as ex:
    				result = {
    					'status':'error',
    					'message':'str(ex)',
    				}
    			return json.dumps(result, indent=indent, sort_keys=sort_keys)
    		return inner
    	return actual_decorator
    
    @json_output(indent=4) #    @actual_decorator
    def do_nothing(a,b=4):			#def do_nothing(a,b=4):	        					
    	return {'status':'done'}	#	return {'status':'done'}
    q='rt'							#do_nothing = json_output(indent=4)(do_nothing)
    print(do_nothing(q,b=54))
    #json_output called
    #('rt',)
    #{'b': 54}
    #{
    #    "status": "done"
    #}
    @json_output #json_output         ,           ,   
    def do_error():
    	return {'status':'error'}
    do_error()
    #json_output called
    #Traceback (most recent call last): 
    #  File "test.py", line 58, in 
    #    do_error()
    #TypeError: actual_decorator() missing 1 required positional argument: 'decorated'
    
    

    json_output(indent=4)は、関数を呼び出してactual_を返すことに相当します.decorator. 複数のモディファイヤは、@構文糖で宣言された順序とは逆の順序で呼び出される関数を同時に装飾することができる.詰めるときは下から上、使うときは上から下.
    装飾類
    クラスでの実装_call__メソッドでは、クラスのオブジェクトインスタンスを呼び出し可能なオブジェクトにし、継承によって機能を追加します.
    from functools import wraps
     
    class logit(object):
        def __init__(self, logfile='out.log'):
            self.logfile = logfile
     
        def __call__(self, func):
            @wraps(func)
            def wrapped_function(*args, **kwargs):
                log_string = func.__name__ + " was called"
                print(log_string)
                #   logfile   
                with open(self.logfile, 'a') as opened_file:
                    #             
                    opened_file.write(log_string + '
    '
    ) # , self.notify() return func(*args, **kwargs) return wrapped_function def notify(self): # logit , pass class email_logit(logit): ''' logit , email ''' def __init__(self, email='[email protected]', *args, **kwargs): self.email = email super(email_logit, self).__init__(*args, **kwargs) def notify(self): # email self.email pass @logit() #logit() def myfunc1(): pass

    @email_logitは@logitと同じ効果を生みますが、ログを打った上で、管理者にメールを1通多く送信します.