Python閉包と装飾器の原理及び実例解析


一、閉め切ってください
クローズドは、関数に相当します。他の関数を入れ子して返します。コードは以下の通りです

def func(name): #       
  def inner_func(age): #     
    print('name: ', name, ', age: ', age)
  return inner_func #        ,      

bb = func('jayson') #       func  ,  inner_func      
bb(28) #       func  ,    ,      
>>
name: jayson , age: 28
二、飾り器
装飾器:関数testを変数として登録した装飾関数deco-->が装飾操作を行った後、変数は関数test()に伝えられました。例えば、装飾器の効果はtest=test-1で、test関数がdecoで飾られた後、testを呼び出して実行するのはtest=test-1です。
1、装飾器はクローズドの原理を利用して、装飾器がクローズドに入ってくるパラメータを関数として区別します。変数ではありません。
注:実は飾り器の中で、関数は変数です。

def deco(func): #   func  。
  print('decoration')
  return func
def test():
  print('test_func')

test = deco(test) #        。   deco  ,        test
>>
#   deco     
decoration

test() #         
>>
test_func
2、以上のコードは

def deco(func): #   func  。
  print('decoration')
  return func

@deco #         test = deco(test),           test  
def test():
  print('test_func')

>>
#   deco     
decoration

test() #         
>>
test_func
3、装飾器(簡易版)

def deco(func): #       func
  print('decoration')
  return func

@deco #     。
def test():
  print('test_func') 
#       ,        deco(test)
>>
decoration

#   test,  test  
test()
>> 
test_func
3、飾り器(アップグレード版)
前のバージョンでは、装飾器+関数を定義する際に、装飾関数の文言が実行されます。
呼び出されていないときに実行しないためには、もう一つの関数を入れ替える必要があります。

def deco(func): 
  print('decoration') #      func   ,     
  def wrapper(): #      ,   wrapper
    print('execute') #      func   ,    
    func() #     
  return wrapper #     wrapper func,    func()  

@deco #   :       。       func      deco(),  deco     
def test():
  print('test_func')
>>
decoration
#  test
test()
>>
execute
test_func
注意:Fnc関数自体に戻り値がある場合は、同様に小包関数に戻ります。

def deco(func): 
  print('decoration')
  def wrapper():
    print('execute')
    a = func() #     ,    
    print('done')
    return a #  func        
  return wrapper

@deco
def test():
  print('test_func')
  return 5 #      
>>
decoration

#  test
test()
>>
execute
test_func
done
 #    test      
3、装飾器(進歩版)
小包関数では、パラメータ形式は、*arg、*kwargに設定されており、より柔軟な関数になります。
test関数パラメータ形式を変更すると、装飾器で同時に変更する必要はありません。

import time

def deco(func):
  def inner(*arg, **kwarg): #       
    begin_time = time.time()
    time.sleep(2)
    a = func(*arg, **kwarg) #     ,       
    end_time = time.time()
    print('    :', end_time - begin_time)
    return a
  return inner

@deco
def test(a):
  print('test function:', a)
  return a

#     
test(5)
>>
test function: 5
    : 2.0003252029418945
 # 5       
4、高次版
ある時、私達はある飾り器の中に括弧が付いています。その原因は上記の飾り器の外にもう一つの関数が付いているからです。

import time

def outer(): #            ,           。(outer   )
  def deco(func): #     ,       
    def inner(*arg, **kwarg): 
      begin_time = time.time()
      time.sleep(2)
      a = func(*arg, **kwarg) 
      end_time = time.time()
      print('    :', end_time - begin_time)
      return a
    return inner
  return deco #   :         

@outer() #         ,      outer()  , test      
def test(a):
  print('test function:', a)
  return a

test(4)
>>
test function: 4
    : 2.000566005706787
 #   4
5、高次終結版
パラメータ付き装飾器(飾り器に括弧、パラメータ付き)

import time

def outer(choose): #            
  if choose==1: #   choose  ,     
    def deco(func):
      def inner(*arg, **kwarg):
        print('decoration1')
        begin_time = time.time()
        time.sleep(2) #   2s
        a = func(*arg, **kwarg) 
        end_time = time.time()
        print('    1:', end_time - begin_time)
        return a
      return inner
    return deco
  
  else:
    def deco(func):
      def inner(*arg, **kwarg): 
        print('decoration2')
        begin_time = time.time()
        time.sleep(5) #   5s
        a = func(*arg, **kwarg) 
        end_time = time.time()
        print('    2:', end_time - begin_time)
        return a
      return inner
    return deco

@outer(1) #   outer    ,        
def test1(a):
  print('test function1:', a)
  return a

@outer(5) #        
def test2(a):
  print('test function2:', a)
  return a


#     2   (2        ,       )
test1(2) #   test1
>>
decoration1
test function1: 2
    1: 2.000072717666626 # 2 
 # test1    

test2(4) #   test2
>>
decoration2
test function2: 4
    2: 5.000797986984253 # 5 
 # test2    
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。