한마디로 말하자면, 함수에 장식을 붙이듯 앞뒤로 원하는 코드를 추가하는 기법이다.
def decorator_name(func):
def inner_func_name(*args, **kwargs):
기존 함수에 추가할 명령
return func(*args, **kwargs)
return inner_func_name
클로저와 비슷하게 생겼지만, 차이점은 "다른 함수를 인자로 받는다"는 점.
예시)
def inner():
print("결과를 출력합니다.")
def outer(func):
def wrapper():
print("-"*20)
func()
print("-"*20)
return wrapper
inner = outer(inner)
inner()
outer가 직접 박스를 그리지 않고 지역함수 wrapper에게 이 작업을 시킨다. wrapper 지역함수가 인수로 전달받은 함수를 대리호출하며 outer는 wrapper함수를 만들어 리턴한다. 이때 리턴하는 지역함수를 inner함수가 다시 대입받는데 이 구문에서 좌우변의 inner는 다른 함수이다.
inner = outer(inner)
여기서 좌변은 원래의 함수 앞뒤에 박스를 그리는 wrapper 함수
우변은 결과를 출력하는 원래의 inner 함수
다시 말하자면, outer로 전달되는 inner는 결과만 출력하는 함수이며, 이 함수는 wrapper지역 함수의 클로저에 기억된다. outer가 리턴하는 지역함수 wrapper를 대입받는 inner는새로 생성한 지역함수에 대한 별명이다. 이제 inner를 호출할때 outer 거칠 필요없이 inner()라고 호출하면 된다.
inner = outer(inner)구문으로 함수를 포장하여 재정의하는 것을 간편하게 표기한 것이 @outer 데코레이터이다. 이 구문은 inner가 outer에 의해 래핑됨을 바로 알 수 있어 직관적이고 함수정의문과 데코레이터가 붙어있어 가독성이 좋다.
def outer(func):
def wrapper():
print("-" *20)
func()
print("-"*20)
return wrapper
@outer
def inner():
print("결과를 출력합니다. ")
inner()
데코레이터는 기존 코드는 그대로 두고 추가적인 처리를 쉽게 할 수 있다는 면에서 편리하다. 한번만 잘 작성해두면 일련의 함수에 공통적으로 적용할 코드를 손쉽게 적용할 수 있고 유지 보수도 쉽다. 함수 실행 전에 특정한 조건을 점검한다거나 로그를 남길 수도 있다.
ref: <파이썬 정복> -김상형 지음