728x90
import time


def clock(func):
    def clocked(*args):         # 내부 함수 clocked() 가 임의 개수의 위치 인수를 받을 수 있도록 정의한다.
        t0 = time.perf_counter()
        result = func(*args)    # clocked() 에 대한 클로저에 자유 변수 func가 들어가야 이 코드가 작동한다.
        elapsed = time.perf_counter()
        name = func.__name__
        arg_str = ', '.join(repr(arg) for arg in args)
        print('[%0.8fs] %s(%s) -> %r' % (elapsed, name, arg_str, result))
        return result
    return clocked

 

 

이함수는 데커레이트된 함수를 호출할 때마다 시간을 측정해서 실행에 소요된 시간, 전달 된 인수,
반환값을 출력하는 데커레이터다.

 

@clock
def factorial(n):
    return 1 if n < 2 else n*factorial(n-1)

 

 

위 코드는 실제로 다음 코드로 실행된다.

 

def factorial2(n):
    return 1 if n < 2 else n*factorial2(n-1)

 

 

따라서 앞의 두 예제에서는 clock()은 factorial() 함수를 func인수로 받는다.
그후 clocked() 함수를 만들어서 반환하는데, 파이썬 인터프리터가 내부적으로 clocked()를
factorial에 할당했다. 실제로 clockdeco_demo 모듈을 임포트해서 factorial의
__name__ 속성을 조사해보면 다음과 같은 결과가 나온다.

 

import clockdeco_demo
clockdeco_demo.factorial.__name__
--> 'clocked'

 

그러므로 factorial은 이제 실제로 clocked()함수를 참조한다.
이제부터 factorial(n)을 호출하면 clocked(n)이 실행된다.
본질적으로 clocked() 함수는 다음과 같은 연산을 수행한다.

 

  1. 초기 시각 t0를 기록한다.
  2. 원래의 factorial() 함수를 호출하고 결과를 저장한다.
  3. 흘러간 시간을 계산한다.
  4. 수집한 데이터를 포맷하고 출력한다.
  5. 2번째 단계에서 저장한 결과를 반환한다.

이 예제 함수는 전형적인 데커레이터 작동 방식을 보여준다.
데커레이트된 함수를 동일한 인수를 받는 함수로 교체하고, (일반적으로) 데커레이트된 함수가
반환해야 하는 값을 반환하면서 추가적인 처리를 수행한다.

728x90

'Python > python - pythonic' 카테고리의 다른 글

약한참조  (2) 2020.12.02
del 과 가비지 컬렉션  (0) 2020.12.02
nonlocal 선언 이 필요한 이유  (0) 2020.11.28
클로저 함수  (0) 2020.11.28
변수 범위 규칙  (0) 2020.11.27