파이썬 데코레이터(Decorator) 이해하기: 사용 이유와 예제

파이썬 데코레이터(Decorator) 이해하기: 사용 이유와 예제

데코레이터는 파이썬의 중요한 기능 중 하나로, 코드를 간결하게 만들고, 읽기 쉽고, 재사용성을 높일 수 있습니다. 이번 글에서는 파이썬 데코레이터가 무엇인지, 왜 사용해야 하는지, 그리고 어떻게 사용하는지에 대해 알아보겠습니다.

▼ 목차

  1. 데코레이터의 정의
  2. 데코레이터가 필요한 이유
  3. 데코레이터의 사용 예제
  4. 데코레이터의 주의점

1. 데코레이터의 정의

데코레이터는 파이썬에서 함수나 메소드에 추가적인 기능을 주입하는 데 사용되는 도구입니다. 이를 통해 기존의 함수나 메소드를 수정하지 않고도 그 기능을 확장할 수 있습니다. 데코레이터는 함수를 인자로 받아 다른 함수를 반환하는 고차 함수입니다. 이 기능은 파이썬의 함수도 객체라는 특성 덕분에 가능합니다.

2. 데코레이터가 필요한 이유

데코레이터는 코드의 재사용성을 향상시키고, 코드를 더욱 깔끔하고 관리하기 쉽게 만듭니다. 또한, 데코레이터를 통해 공통적인 패턴을 캡슐화하고, 이를 다양한 함수나 메소드에 적용할 수 있습니다.

3. 데코레이터의 사용 예제

예제 1

이 예제에서는 로깅 기능을 구현한 함수를 클로저와 데코레이터를 각각 사용하여 작성해 보겠습니다.

1. 클로저를 이용한 로깅 함수

def logger_closure(msg):
    def log_message():  # 클로저 함수
        print(f'Log: {msg}')  # 로그 메시지 출력
    return log_message

# 클로저를 이용해 log_hi 함수 생성
log_hi = logger_closure('Hi')
log_hi()  # 'Log: Hi' 출력


2. 데코레이터를 이용한 로깅 함수

def logger_decorator(func):
    def wrapper(*args, **kwargs):
        print(f'Log: {func.__name__} 함수 호출')  # 로그 메시지 출력
        return func(*args, **kwargs)  # 원래 함수 실행
    return wrapper

@logger_decorator  # 데코레이터를 이용해 my_function에 로깅 기능 추가
def my_function():
    print('Hello!')

my_function()  # 'Log: my_function 함수 호출', 'Hello!' 출력

☞ 이 두 예제를 비교해 보면, 로깅 기능이 필요한 여러 함수에 대해 데코레이터를 적용하면 코드의 재사용성이 높아집니다. 또한, 함수의 기능을 확장하면서도 원래 함수의 로직을 그대로 유지할 수 있다는 것을 알 수 있습니다. 이것은 데코레이터의 주요한 이점 중 하나입니다.

예제 2

이 예제에서는 타이머 기능을 구현한 함수를 클로저와 데코레이터를 각각 사용하여 작성해 보겠습니다.

1. 클로저를 이용한 타이머 함수

import time

def timer_closure(func):
    def wrapper(*args, **kwargs):
        def timer():
            start_time = time.time()  # 시작 시간 측정
            result = func(*args, **kwargs)  # 원래 함수 실행
            end_time = time.time()  # 종료 시간 측정
            print(f"{func.__name__} 함수의 실행 시간: {end_time - start_time}초")
            return result
        return timer
    return wrapper

my_function_timer = timer_closure(my_function)
result = my_function_timer(1000000)()  # timer 함수에 인자를 전달

# 출력
my_function 함수의 실행 시간: 0.12179040908813477초


2. 데코레이터를 이용한 타이머 함수

import time

def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()  # 시작 시간 측정
        result = func(*args, **kwargs)  # 원래 함수 실행
        end_time = time.time()  # 종료 시간 측정
        print(f"{func.__name__} 함수의 실행 시간: {end_time - start_time}초")
        return result
    return wrapper

@timer_decorator  # 데코레이터를 사용해 my_function에 타이머 기능 추가
def my_function(n):
    total = 0
    for i in range(n):
        total += i
    return total

result = my_function(1000000)  # 함수 실행 및 실행 시간 출력

# 출력
my_function 함수의 실행 시간: 0.12572193145751953초

☞ 이 두 예제를 비교해 보면, 데코레이터를 사용하면 클로저를 사용하는 것보다 코드가 훨씬 간결해지고, 원래 함수의 로직을 그대로 유지하면서 새로운 기능을 추가하기 쉽다는 것을 알 수 있습니다. 이는 데코레이터의 주요 장점 중 하나입니다.

4. 데코레이터의 주의점

데코레이터를 사용할 때 몇 가지 주의할 점이 있습니다. 첫째, 데코레이터는 함수의 서명을 변경할 수 있으므로 원래 함수의 메타데이터를 유지하려면 ‘functools.wraps’를 사용해야 합니다. 둘째, 데코레이터는 코드의 실행 순서와 범위를 변경하므로 사용에 주의해야 합니다.


☞ 파이썬의 데코레이터는 코드의 재사용성과 가독성을 높이는 데 매우 유용합니다. 하지만 사용에 주의해야 할 점도 있으므로, 데코레이터를 활용할 때는 이를 충분히 이해하고 사용하는 것이 중요합니다.

참고 자료

함께 보면 좋은 이전 게시글

위로 스크롤