[Python] Decorator와 API 설계

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를 붙여주기만 하면 되기 때문!