파이썬은 데코레이터(decorator)라는 기능을 제공한다. 지금까지 클래스에서 메서드를 만들 때 @staticmethod , @classmethod, @abstractmethod 등을 붙였는데, 이렇게 @ 로 시작하는 것들이 데코레이터이다.

데코레이터 만들기

데코레이터는 함수를 수정하지 않은 상태에서 추가 기능을 구현할 때 사용한다.

예를 들어 함수의 시작과 끝을 출력하고 싶다면 다음과 같이 함수 시작, 끝 부분에 print를 넣어주어야한다.

def hello():
    print("hello 함수의 시작")
    print("hello")
    print("hello 함수의 끝")

def world():
    print("world 함수의 시작")
    print("world")
    print('world 함수의 끝')

hello()
world()

만약 다른 함수도 시작과 끝을 출려하고 싶다면 함수를 만들 때마다 print를 넣어야 한다. 따라서 함수가 많아지면 매우 번거로워 진다. 이 경우에 데코레이터를 활용하면 편리해진다.

def trace(func):
    def wrapper():
        print(func.__name__, "함수 시작")
        func()
        print(func.__name__, '함수 끝')
    return wrapper

def hello():
    print("hello")

def world():
    print("world")

trace_hello = trace(hello)
trace_hello()
trace_world = trace(world)
trace_world()

@로 데코레이터 사용하기

이제 @을 사용해서 좀 더 간편하게 데코레이터를 사용해보자. 다음과 같이 호출할 함수 위에 @데코레이터 형식으로 지정한다.

def trace(func):
    def wrapper():
        print(func.__name__, "함수 시작")
        func()
        print(func.__name__, '함수 끝')
    return wrapper

@trace
def hello():
    print("hello")

@trace
def world():
    print("world")

hello()
world()

데코레이터를 그림으로 표현하면 다음과 같은 모양이 된다.

데코레이터를 여러 개 지정하기

함수에는 데코레이터를 여러개 지정할 수 있다. 이때 데코레이터가 실행되는 순서는 위에서 아래 순이다.

매개변수와 반환값을 처리하는 데코레이터 만들기

매개변수와 반환값을 처리하는 데코레이터는 어떻게 만드는지 알아보자

def trace(func):
    def wrapper(a, b): # 호출할 함수 add(a, b)의 매개변수와 똑같이 지정
        r = func(a, b)
        print('{0}(a={1}, b={2}) -> {3}'.format(func.__name__, a, b, r))
        return r
    return wrapper

@trace
def add(a, b):
    return a + b

print(add(10, 20))
add(a=10, b=20) -> 30
30