Decorator란?
Decorator는 Python에서 사용되는 일종의 Semantic Sugar의 일종이다.
이름에서 알 수 있듯이 함수를 꾸며주는 역할을 한다.
함수를 꾸며준다라는 행위를 조금 더 명확하게 기술하자면,
함수를 수정하지 않고 함수에 기능을 추가하는 행위
라고 할 수 있다. 코드를 통해 바로 살펴보자.
def decorator(function): #Decorate할 함수를 인자로 받음
def wrapper(): #Decoration 함수 내부에서 인자로 받은 함수 호출
print("function start");
function()
print("function end");
return wrapper
@decorator #@로 Decorator를 호출
def fucking_function():
print("I AM FUNCTION")
Python
출력 결과는 아래와 같다.
function start
I AM FUNCTION
function end
Python
Decorated 함수에 인자가 있는 경우
def decorator(function): #Decorate할 함수를 인자로 받음
def wrapper(name): #Decoration 함수 내부에서 인자로 받은 함수 호출
print("function start");
function(name)
print("function end");
return wrapper
@decorator #@로 Decorator를 호출
def fucking_function(name):
print("I AM FUNCTION" + name)
Python
꾸며주는 함수에 똑같이인자를 적어주면 된다. 인자가 여러개라면?
def decorator(function): #Decorate할 함수를 인자로 받음
def wrapper(*args, **kwargs): #Decoration 함수 내부에서 인자로 받은 함수 호출
print("function start");
function(name)
print("function end");
return wrapper
@decorator #@로 Decorator를 호출
def fucking_function(name):
print("I AM FUNCTION" + name)
Python
*args, **kwargs 를 통해 가변인자, 가변 키워드 인자를 받아올 수 있다.
Decorator 함수에 인자가 있는 경우
위와 다르다!! Decorated가 (피꾸밈당하는) 아니라 Decorator (꾸며주는) 함수에 인자를 전달하고 싶은 경우 는 아래와 같이 하면 된다.
def i_want_parameter(parameter):
def decorator(function): #Decorate할 함수를 인자로 받음
def wrapper(*args, **kwargs): #Decoration 함수 내부에서 인자로 받은 함수 호출
print("function start" +parameter);
function(name)
print("function end" +parameter);
return wrapper
return decorator
@i_want_parameter(parameter)
def fucking_function(name):
print("I AM FUNCTION" + name)
Python
Decorator 함수는 일반적으로 Decorated함수를 인자로 받기 때문에 다른 매개변수를 넣어줄 수 없다.
따라서 함수를 만드는 함수를 정의해서 함수를 반환하게 하면 된다 (ㄹㅇ힙합)
@wraps 이용
위와 같이 Decorator를 사용하면 몇가지 문제가 있다. Decorator가 함수를 덮어 씌우면서
print fucking_function.__name__
Python
같은 구문을 사용할 수가 없다. (decorator가 출력된다.)
이게 뭐가 문젠데? 라고 생각할 수도 있지만, Swagger 등을 이용해서 API Sheet 를 만들거나 하면 이제 메롱인 상황이 발생한다.
아무튼 여러가지 문제가 있으니까 그냥 무조건 아래처럼 하면 된다.
from functools import wraps
def decorator(function): #Decorate할 함수를 인자로 받음
@wraps(function) #@wraps를 wrapper위에 호출한다
def wrapper(*args, **kwargs): #Decoration 함수 내부에서 인자로 받은 함수 호출
print("function start");
function(name)
print("function end");
return wrapper
@decorator #@로 Decorator를 호출
def fucking_function(name):
print("I AM FUNCTION" + name)
Python
functools의 wraps 모듈을 불러오고, wrapper위에다가 wraps를 호출하면 된다.
API 설계에서의 이용
기본적으로 Flask에서는 Decorator를 이용해서 라우팅을 하기도 하거니와, (django는 모름 ㅎ)
Decorator를 이용하면 Authenticate를 쉽게 만들 수 있다.
따로 인증 라우터를 제작할 필요 없이, JWT를 검증하는 데코레이터 함수를 만들고, 모든 라우터에다가 @decorator를 붙여주기만 하면 되기 때문!