예를 들어 파이썬 장식기 설명

6409 단어 python장식기
Python에서 함수는 매개 변수로 하나의 함수를 전달할 수 있고 함수도 변수에 복사하여 변수를 통해 함수를 호출할 수 있다.장식기는 하나의 함수의 기능을 확장하고 함수를 위한 장식기 주석을 만들 수 있으며 장식기 안에 정의된 기능을 모든 함수에 미리 실행하여 코드의 복용 정도를 높일 수 있다.
지금 이런 장면이 있어요.

카드를 끊다


인터넷 회사에는 각종 직원, 프로그래머, 프론트 데스크...프로그래머는 컴퓨터를 켜기 전에 카드를 쳐야 하고, 프론트는 일찍 와서 문을 열어야 한다. (나도 잘 모르겠다. 누가 문을 열어야 하는지, 여기는 프론트가 문을 열어야 한다고 가정한다.) 프론트가 문을 열기 전에도 카드를 쳐야 한다.즉, 카드를 치는 것은 모든 직원의 가장 먼저 하는 공공 동작이다. 그러면 카드를 치는 이 기능을 추출하여 공공 논리로 삼을 수 있다.

일반 함수 호출 방법


자연히 생각하면 다음과 같이 실현될 수 있다.

def di(f):
  print('%s  , ...' % f.__name__)
  return f()


def boot():
  print(' ')


def open():
  print(' ')


if __name__ == '__main__':
  """
   , , 。
  """
  di(boot)
  di(open)
f.__를 인쇄할 수 있는 함수 di (f) 정의됨name__즉 f의 함수 이름 정보를 f()의 실행 결과를 되돌려줍니다.
참고: __name__모듈로 가져오면 module.__name__모듈 자신의 이름입니다. 모듈이 스크립트로 실행되면 __main__.
실행 결과:
boot 카드, 방울...
켜다
오픈 카드, 방울...
문을 열다
이렇게 설계하면 많은 함수를 호출해야 하기 때문에 번거롭기 때문에 장식기가 쓸모가 있다.

단순 장식기와 @ 문법 설탕


장식기: 코드가 실행되는 동안 동적으로 기능을 추가하는 방식을 장식기(Decorator)라고 합니다.

단순 장식기


di(f) 방법을 정의하든지, 아니면 실행할 논리적 함수를 매개 변수로 전송하든지, wrapper 함수를 정의하든지, 반환값은 f의 실행 결과입니다.
if__name__ == '__main__':이 장식기를 호출하여 정의된 함수를 수정하지 않고 실행 중 동적 추가 기능인'카드놀이'를 합니다.

import functools

#  
def di(f):
  """
   , , 。
  :param f:  
  :return:
  """
  #  __name__ wrapper()
  @functools.wraps(f)
  def wrapper():
    print('%s  , ...' % f.__name__)
    return f()
  return wrapper


def boot():
  print(' ')


def open():
  print(' ')


if __name__ == '__main__':

  #  , 
  a = di(boot)
  a1 = di(open)
  print(a.__name__) #  wrapper  @functools.wraps(f)  boot
  a()
  a1()
di(boot)의 반환값 a는 wrapper 함수입니다. a()를 통해 wrapper 함수를 호출하여boot의 반환값을 얻습니다.같은 이치로, di(open)와 같다.

결과


boot
boot 카드, 방울...
켜다
오픈 카드, 방울...
문을 열다
di(boot)의 반환값 a가 wrapper 함수이기 때문에 print(a._name__)결과는 당연히 wrapper입니다. 저희는 boot였으면 좋겠습니다. 어떡하죠,functools.wraps (f) 이 메모는 원본 함수 boot의 __name__등속성이 wrapper()에 복사되어 이 줄의 코드 주석도 실행될 수 있습니다. 그러면 print(a._name__)결과는 래퍼

두번째 @ 문법 설탕을 통해서도 장식기를 함수에 적용할 수 있으니 추천합니다.


import functools

def di(f):
  """
   , , 。
  :param f:  
  :return:
  """
  #  __name__ wrapper()
  @functools.wraps(f)
  def wrapper():
    print('%s  , ...' % f.__name__)
    return f()
  return wrapper


# @  
@di
def boot2():
  print(' ')


@di
def open2():
  print(' ')
  
  
if __name__ == '__main__':

  #  ,@  
  boot2()
  open2()
@di 표기는 a2 = di (boot2) a2 () 와 같습니다.이렇게 번거롭게 할 필요는 없습니다. @ 기호 표시를 넣었기 때문에boot2 () 로 장식기를 호출하면 됩니다.

결과


boot2 카드 걸기, 방울...
켜다
오픈2 카드, 방울...
문을 열다

업무 논리 함수는 매개 변수가 필요하다


비즈니스 논리 함수에는 다음과 같은 매개변수가 필요할 수 있습니다.

def boot(name):
  print('%s  ' % name)
그러면 앞의 장식기를 다음과 같이 수정하면 됩니다.

import functools

#  
def di(f):
  """
   , , 。
  :param f:  
  :return:
  """
  #  __name__ wrapper()
  @functools.wraps(f)
  def wrapper(*args, **kwargs):
    print('%s  , ...' % f.__name__)
    return f(*args, **kwargs)
  return wrapper


@di
def boot(name):
  print('%s  ' % name)


if __name__ == '__main__':
  boot('keguang')
결과:
boot 카드, 방울...
keguang 켜기
wrapper에도 *args, *kwargs 파라미터를 추가하여boot에서 f(*args, *kwargs)를 직접 호출하면 됩니다.참고로
  • *args: 수조 파라미터를 전송할 수 있습니다
  • *kwargs: k-v 쌍의 매개 변수를 전송할 수 있습니다
  • 선후 순서가 대응하고 수조 파라미터가 앞에 있다.예:
    
    def f(*args, **kwargs):
      print('args=', args)
      print('kwargs=', kwargs)
    
    print(f(1, 2, 3, a = 'a', b = 'b'))
    
    #  
    # args= (1, 2, 3)
    # kwargs= {'a': 'a', 'b': 'b'}

    파라미터가 있는 장식기


    만약에 장식기에도 파라미터가 있다면, 예를 들어 지금 만약에 어떤 직원이 아침에 일찍 출근한다면<9:00, 우리는 칭찬을 할 수 있다. 그러면 앞의 di() 밖에 함수를 한 겹만 끼워야 한다,di_args면 돼요. 래퍼 안에서.이 매개 변수 사용하기
    
    import functools
    
    #  
    def di_args(time):
      def di(f):
        """
         , , 。
        :param f:  
        :return:
        """
        #  __name__ wrapper()
        @functools.wraps(f)
        def wrapper(*args, **kwargs):
          if time < '9:00':
            print(' , 。。。')
    
          print('%s  , ...' % f.__name__)
          return f(*args, **kwargs)
        return wrapper
      return di
    
    
    @di_args('8:00')
    def boot(name):
      print('%s  ' % name)
    
    
    if __name__ == '__main__':
      boot('keguang')
    매개변수는 @di_args('8:00')를 입력하면 됩니다. 약간 자바에 있는 주석과 같습니다.마지막으로 boot('keguang')을 통해 호출하면 됩니다. 결과:
    일찍 왔네, 잘했어...
    boot 카드, 방울...
    keguang 켜기

    클래스 장식기


    클래스 장식기는 주로 클래스에 의존하는 __call__메서드, @ 형식으로 장식기를 함수에 추가하면 이 메서드가 호출됩니다.
    
    #  
    class di(object):
      def __init__(self, f):
        self._f = f
    
      def __call__(self, *args, **kwargs):
        print('decorator start...')
        self._f()
        print('decorator end...')
    
    
    @di
    def boot():
      print(' ')
    
    
    if __name__ == '__main__':
      boot()
    @di 장식기 표지를 추가하면 boot으로 di 클래스를 실례화하고 __call__함수,object는 이 클래스가 모든 종류의 매개 변수를 전달할 수 있음을 나타냅니다.
    실행 결과
    decorator start...
    켜다
    decorator end...
    장식기는 전형적인 응용 장면이 있는데 로그 로그를 치는 것이다. 만약에 모든 논리가 로그 기록 프로그램의 운행 상황을 필요로 한다면 이런 논리(함수)에 로그 모듈 장식기를 추가하면 상응하는 목적을 달성할 수 있다.
    이상은 예를 들어 Python 장식기의 상세한 내용을 설명하고,python 장식기에 대한 더 많은 자료는 저희 다른 관련 문장에 주목하세요!

    좋은 웹페이지 즐겨찾기