Python은 간결한 문법과 데이터 분석, 웹 개발 등 다양한 분야에서 강력한 응용 프로그램을 지원하는 덕분에 좋아하는 프로그래밍 언어입니다.
하지만 오랜 기간 코드를 작성하면서도 데코레이터 기능을 거의 사용하지 않았습니다. 클래스의 정적 메서드를 데코레이트하기 위한 @staticmethod
를 사용하는 경우를 제외하면 말이죠.
그래서 이번 글에서는 데코레이터의 개념을 깊이 탐구하고, 파이썬 코드의 효율성을 높일 수 있는 실용적인 데코레이터 5가지를 소개하고자 합니다.
데코레이터(Decorator)란 무엇인가?
데코레이터는 파이썬의 강력한 언어 기능으로, 원래의 함수 코드를 수정하지 않고도 동적으로 기능을 추가하거나 함수의 동작을 수정할 수 있습니다. 데코레이터는 기본적으로 다른 함수나 클래스를 인자로 받아 새로운 함수나 클래스를 반환하는 함수입니다.
데코레이터는 함수를 확장하거나 감싸는 간결하고 우아한 방법을 제공하여 코드의 가독성과 유지보수성을 향상시킵니다.
주로 다음과 같은 상황에서 데코레이터가 사용됩니다:
- 로깅, 성능 분석, 입력 유효성 검사 등 추가적인 기능이나 로직을 추가할 때.
- 캐시 결과, 재시도 메커니즘 추가 등 함수의 동작을 수정할 때.
- 주요 비즈니스 로직에서 공통적으로 발생하는 문제를 분리할 때.
이제 간단하지만 유용한 5가지 데코레이터를 알아보겠습니다.
01. timer
: 함수의 실행 시간 측정
코드 성능 최적화는 매우 중요합니다. 이 데코레이터는 특정 함수의 실행 시간을 추적하고 경과 시간을 출력합니다. 이 데코레이터를 사용하여 코드의 병목 지점을 쉽게 파악하고 중요한 부분을 최적화할 수 있습니다.
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
return result
return wrapper
데코레이터를 사용하려면 원하는 함수 위에 @
기호를 사용해 적용하면 됩니다.
@timer
def train_model():
print("Starting the model training function...")
time.sleep(5)
print("Model training completed!")
train_model()
# 출력:
Starting the model training function…
Model Training completed!
Execution time: 5.006425619125366 seconds
02. debugger
: 디버깅을 쉽게
각 함수의 입력과 출력을 출력하여 디버깅을 더 쉽게 할 수 있는 래퍼 함수를 만들 수 있습니다. 이 방법은 여러 개의 print 문을 사용하지 않고도 함수의 실행 흐름을 쉽게 파악할 수 있습니다.
def debugger(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with args: {args} kwargs: {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned: {result}")
return result
return wrapper
@debugger
def add_numbers(x, y):
return x + y
add_numbers(7, y=5)
# 출력:
Calling add_numbers with args: (7,) kwargs: {'y': 5}
add_numbers returned: 12
03. memoize
: 결과 캐싱
코드에서 일부 반복 실행되는 부분은 큰 컴퓨팅 자원을 소모할 수 있습니다. 이 경우 memoize
데코레이터를 사용하여 함수 호출 결과를 캐싱할 수 있습니다.
def memoize(func):
cache = {}
def wrapper(*args):
if args in cache:
return cache[args]
else:
result = func(*args)
cache[args] = result
return result
return wrapper
피보나치 수 계산 함수에 캐싱을 적용하면, 동일한 입력에 대해 함수가 한 번만 실행되고 이후에는 캐시된 결과를 사용하게 됩니다.
@memoize
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
캐싱을 사용하지 않은 경우와 비교해 보면, 캐싱된 버전은 몇 밀리초밖에 걸리지 않는 반면, 캐싱되지 않은 버전은 거의 1분이 걸릴 수 있습니다.
04. retry
: 재시도 로직
데이터 과학과 소프트웨어 개발에서 외부 시스템에 의존하는 경우가 많지만, 모든 외부 시스템이 안정적이지는 않습니다. 예기치 않은 오류가 발생했을 때, 코드가 잠시 기다렸다가 다시 시도하도록 할 수 있습니다. 이 재시도 로직을 데코레이터로 구현하여 쉽게 적용할 수 있습니다.
import time
def retry(max_attempts, delay=1):
def decorator(func):
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
print(f"Attempt {attempts} failed: {e}")
time.sleep(delay)
print(f"Function failed after {max_attempts} attempts")
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def fetch_data(url):
print("Fetching the data..")
raise TimeoutError("Server is not responding.")
fetch_data("https://example.com/data")
이 코드는 최대 3번까지 2초 간격으로 재시도합니다.
05. exception_handler
: 예외 처리 간소화
exception_handler
데코레이터는 함수에서 발생하는 예외를 잡아 처리할 수 있습니다. 필요에 따라 로깅하거나 추가적인 오류 처리를 수행할 수 있습니다.
def exception_handler(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"An exception occurred: {str(e)}")
return wrapper
@exception_handler
def divide(x, y):
result = x / y
return result
divide(10, 0)
# 출력:
An exception occurred: division by zero
이 데코레이터는 코드를 단순화하고 예외 처리와 오류 로깅을 위한 일관된 절차를 설정하는 데 매우 유용합니다.
요약
데코레이터는 함수에 새로운 동작을 적용하는 매우 편리한 방법입니다. 데코레이터를 사용하면 복잡한 작업을 간소화하고 코드 가독성을 높이며, 생산성을 향상시킬 수 있습니다.
데코레이터는 파이썬의 강력한 기능 중 하나이며, 적절히 활용하면 코드의 유지보수성과 확장성을 높일 수 있습니다. 데코레이터를 사용해 여러분의 파이썬 코드를 한 단계 더 발전시켜보세요. 😊
'Language > Python' 카테고리의 다른 글
일상 작업을 자동화하는 10가지 Python 스크립트 (1) | 2024.12.05 |
---|---|
파이썬에서 함수형 프로그래밍 실습 (0) | 2024.11.16 |
[Python] 디자인 패턴 사용 방법 (2) | 2024.11.14 |
알아두면 유용한 12가지 파이썬 라이브러리 (3) | 2024.11.12 |
Pandas 마스터하기: 데이터 조작을 위한 고급 기술 (82) | 2024.01.28 |
IT 기술과 개발 내용을 포스팅하는 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!