파이썬을 쓰다보면 ’@’ 이런 모양을 종종 만나게 된다. 저것은 데코레이터(decorator)라고 하는 것이다. 난 데코레이터를 처음 봤을때 ‘오 귀여운 골뱅이네’라고 생각했다. 플라스크를 처음 사용할 때도 귀여운 골뱅이를 보았다.
from flask import Flask
app = Flask(name)
@app.route("/")
def hello():
return "Hello World!"
위 예시 코드에서 ‘@app.route(”/”)’ 이 부분이 바로 데코레이터다.
그렇다면 데코레이터는 무슨 일을 할까?
코드를 바꾸지 않고 기존 함수를 수정할 때 사용할 수 있다. 데코레이터는 함수를 인자로 받아 다른 함수를 출력한다. 직관적으로 이해가 되지 않으니 예제를 한번 만들어보자.
def document_it(func):
def new_function(*args):
print('Running function:', func.name)
print('Arguments:', args)
result = func(*args)
print('This is result:', result)
return result
return new_function
함수의 이름과 인자, 그리고 결과를 알려주는 데코레이터 함수를 만들었다! 이 데코레이터 함수는 함수를 인자로 받아 새로운 함수를 반환한다. *args는 파이썬의 위치인자이다. **kwargs를 넣으면 키워드 인자까지 알려줄 수 있지만 예제에선 위치인자만 넣어보았다.
그럼 한번 사용해보자.
def give_me_beer(a):
return "I need {} more beer!!".format(a)
give_me_beer(5)
>> I need 5 more beer!!
another_give_me_beer = document_it(give_me_beer)
another_give_me_beer(900)
>> Running function: give_me_beer
>> Arguments: 900
>> This is result: I need 900 more beer!!
>> I need 900 more beer!!
위에서는 수동으로 데코레이터함수를 할당했다. 그래서 귀여운 골뱅이 ’@’ 모양을 볼 수 가 없다.
데코레이터를 사용하고 싶다면 사용하고 싶은 함수 위에 ‘@decorator_name’을 쓰면 된다.
@document_it
give_me_beer(5)
>> I need 5 more beer!!
give_me_beer(900)
>> Running function: give_me_beer
>> Arguments: 900
>> This is result: I need 900 more beer!!
>> I need 900 more beer!!
짠 이제 givemebeer만 실행해도 내가 원하는 데코레이터 함수가 적용되어 작동한다. 예제에서는 하나만 썼지만 데코레이터는 여러개를 붙여서 사용할 수도 있다.
데코레이터를 어떤 경우에 쓸까
함수 마다 실행되는 시간을 측정해야 되는 경우가 있다고 가정해보자. 함수가 약 20개 정도 되는데 모든 함수의 소스코드에 실행 시간을 측정하는 코드를 짜 넣는 것은 비효율적이다. 게다가 매우 귀찮은 과정이 될 것이다.
그럴 때 시간을 실행 시간을 측정하는 데코레이터 함수를 만들어 함수의 위에다 붙여주기만 하면 각 함수의 코드를 변경하지 않아도 실행 시간을 측정할 수 있지 않을까?