[Python] Decorator
어떤 함수를 수행하기에 앞서 반복되는 동작을 수행시키고 싶을 때 decorator 기능을 사용한다. 예를 들면 특정 함수의 성능을 측정하고 싶을 때 수행 앞뒤에 시간측정이 필요 할 것이다. 이럴 때 decorator 기능을 사용하면 유용하다.
def big_number(n): return n ** n ** n def make_func_alarm(func): def new_func(*args, **kwargs): print("함수를 시작합니다.") result = func(*args, **kwargs) print('함수를 종료합니다.') return result return new_func new_func = make_func_alarm(big_number) new_func(6)
함수를 시작합니다. 함수를 종료합니다. 265911… |
위에 make_func_alarm
함수 구조를 보면 함수 내부에 closure인 new_func
가 존재한다.
코드 설명을 해보자면, 함수 선언부 밖 에 new_func
은 make_func_alarm
의 return인 closure가 new_func
이 될 것이다. 즉 외부의 new_func
은 입력 인수인 big_number
함수 객체가 assign 된다.
Closure 함수 내부를 보면 result = func(*args, **kwargs)
라고 되있기 때문에 가변인자와 가변 키워드 인자로 함수의 입력을 받는다. 위 예제 코드에선 6이 입력으로 들어오면서 해당 값이 big_number
의 인자로 들어간다.
import time def make_time_checker(func): def new_func(*args, **kwargs): start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() print('실행시간:', end_time - start_time) return result return new_func new_func = make_time_checker(big_number) new_func(7)
실행시간: 0.14005279900004552 37598…. |
일반적으로 함수의 앞뒤에 시간을 측정하기 위해 위 코드를 사용하면 유용하다.
Python에선 이런 decorator를 특정 키워드 @를 통해 사용한다. 실제 위 decorator가 사용된 코드를 다음과 같이 변경 할 수 있다.
import time def make_time_checker(func): def new_func(*args, **kwargs): start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() print('실행시간:', end_time - start_time) return result return new_func @make_time_checker def big_number(n): return n ** n ** n # Same with the below # big_number = make_time_checker(big_number) big_number(7)
시간을 재는 것 뿐만 아니라 trace log를 남기는 기능 또한 필요하다. 예를 들면 함수 수행 전과 수행 후의 log를 찍어야할 경우가 있다. 이럴 때 아래 코드를 사용하면 유용하다.
enable_tracing = True if enable_tracing: debug_log = open("debug.log","w") def trace(func): if enable_tracing: def callf(*args,**kwargs): debug_log.write("Calling %s: %s, %s\n"% (func.__name__,args,kwargs)) r = func(*args,**kwargs) debug_log.write("%s returned %d\n"% (func.__name__,r)) return r return callf else : return func @trace def square(x): return x*x square(100)
10000 |
위 코드는 enable_tracing
변수를 통해 log tracing 기능을 on/off 할 수 있다.