[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 할 수 있다.