티스토리 뷰
목차
서론
프로젝트를 하다 보면 코드를 줄이면서도 기능을 강화하는 방법을 찾게 됩니다. 특히 함수나 메서드에 기능을 더하고 싶을 때는 데코레이터가 아주 좋은 도구가 될 수 있어요. 처음엔 조금 낯설지만, 익숙해지면 반복 작업을 줄여주고 코드의 가독성도 높여줍니다. 제 경험상, 처음엔 단순한 예제로 데코레이터가 어떤 식으로 작동하는지 천천히 익혀가는 게 좋습니다. 이제, Python에서 데코레이터를 쉽게 시작해 봅시다.
1. 데코레이터란 무엇인가?
Python에서 **데코레이터(decorator)**는 함수를 감싸 추가적인 기능을 부여하는 도구입니다. 데코레이터를 사용하면 함수를 수정하지 않고도 기능을 확장할 수 있어서, 특히 중복 코드 줄이기에 유용합니다. 함수 위에 @데코레이터_이름 형태로 추가하여 데코레이터를 적용할 수 있습니다.
1.1 기본적인 데코레이터 구조
데코레이터는 보통 다른 함수를 매개변수로 받아서 내부에서 새 함수를 정의한 후, 이 새로운 함수를 반환합니다. 이렇게 하면 감싸진 함수가 실행되면서 데코레이터가 제공하는 추가 기능이 더해집니다.
def decorator_function(original_function):
def wrapper_function():
print("데코레이터로 확장된 기능입니다.")
return original_function()
return wrapper_function
1.2 데코레이터의 기본 사용법
데코레이터를 함수에 적용하려면 함수 정의 바로 위에 @데코레이터_이름을 추가합니다. 이때 데코레이터가 먼저 실행되고, 그 후에 원래 함수가 실행됩니다.
@decorator_function
def say_hello():
print("안녕하세요!")
say_hello()
# 출력:
# 데코레이터로 확장된 기능입니다.
# 안녕하세요!
이제 say_hello 함수가 호출될 때마다 데코레이터로 확장된 기능입니다.라는 메시지가 함께 출력됩니다.
2. 함수형 데코레이터 만들기
2.1 데코레이터의 매개변수 전달
데코레이터를 사용하다 보면 매개변수를 받아서 처리하는 함수에도 적용해야 할 때가 많습니다. 이를 위해 데코레이터 내부에서 *args와 **kwargs를 활용하여 어떤 매개변수라도 처리할 수 있도록 합니다.
def decorator_function(original_function):
def wrapper_function(*args, **kwargs):
print("데코레이터 실행 중")
return original_function(*args, **kwargs)
return wrapper_function
2.2 매개변수 있는 함수에 데코레이터 적용하기
예를 들어, 아래는 인사말과 이름을 매개변수로 받아 출력하는 함수입니다. 이 함수에 데코레이터를 적용하여 확장된 기능을 추가해 보겠습니다.
@decorator_function
def greet(greeting, name):
print(f"{greeting}, {name}님!")
greet("안녕하세요", "철수")
# 출력:
# 데코레이터 실행 중
# 안녕하세요, 철수님!
greet 함수는 데코레이터가 매개변수를 처리하면서 확장된 기능을 더한 후 실행됩니다.
3. 데코레이터의 다양한 활용 사례
데코레이터는 단순히 출력 메시지를 추가하는 것 이상의 다양한 활용이 가능합니다. 다음은 데코레이터를 실무에서 활용할 수 있는 몇 가지 예시입니다.
3.1 실행 시간 측정 데코레이터
코드의 실행 시간을 확인하고 싶을 때, 직접 시간을 체크하는 코드를 반복 작성하는 대신, 데코레이터로 실행 시간 측정 기능을 구현할 수 있습니다.
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
def sample_task():
time.sleep(2)
print("작업 완료")
sample_task()
# 출력:
# 작업 완료
# sample_task 함수 실행 시간: 2.002 초
3.2 접근 제어 데코레이터
특정 조건을 만족하는 사용자만 함수를 사용할 수 있도록 제한하는 접근 제어를 데코레이터로 쉽게 구현할 수 있습니다.
def access_control_decorator(func):
def wrapper(user_role):
if user_role == "admin":
return func()
else:
print("접근 권한이 없습니다.")
return wrapper
@access_control_decorator
def sensitive_task():
print("민감한 작업을 수행 중입니다.")
sensitive_task("admin") # "민감한 작업을 수행 중입니다." 출력
sensitive_task("guest") # "접근 권한이 없습니다." 출력
access_control_decorator는 user_role을 검사하여, 적절한 권한이 있을 때만 원래 함수를 실행합니다.
3.3 로그 기록 데코레이터
프로그램 실행 중 발생하는 중요한 작업들을 기록하기 위해 로그 데코레이터를 사용할 수 있습니다.
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"{func.__name__} 함수가 실행되었습니다.")
return func(*args, **kwargs)
return wrapper
@log_decorator
def data_processing():
print("데이터 처리 중")
data_processing()
# 출력:
# data_processing 함수가 실행되었습니다.
# 데이터 처리 중
이처럼 log_decorator는 함수 호출 기록을 남길 때 매우 유용하게 사용할 수 있습니다.
4. 클래스를 사용한 데코레이터
Python에서는 클래스를 데코레이터로 사용할 수도 있습니다. 클래스 데코레이터는 주로 데코레이터가 상태를 유지해야 하는 경우에 유용합니다.
4.1 기본 클래스 데코레이터 구조
클래스 데코레이터는 __call__ 메서드를 정의하여 데코레이터처럼 작동하게 합니다. 함수 호출 시마다 __call__ 메서드가 실행됩니다.
class ClassDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("클래스 데코레이터 실행")
return self.func(*args, **kwargs)
@ClassDecorator
def display_message():
print("메시지를 출력합니다.")
display_message()
# 출력:
# 클래스 데코레이터 실행
# 메시지를 출력합니다.
4.2 클래스 데코레이터로 상태 관리하기
예를 들어 함수가 몇 번 호출되었는지 추적하려면 클래스를 사용해 상태를 유지할 수 있습니다.
class CallCounter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} 호출 횟수: {self.count}")
return self.func(*args, **kwargs)
@CallCounter
def sample_function():
print("샘플 함수 실행")
sample_function()
sample_function()
# 출력:
# sample_function 호출 횟수: 1
# 샘플 함수 실행
# sample_function 호출 횟수: 2
# 샘플 함수 실행
이 클래스 데코레이터는 호출 횟수를 카운팅하여 상태를 유지합니다. 함수가 호출될 때마다 카운팅되어 기록됩니다.
5. 실습 예제 - 데코레이터를 직접 만들어 보기
5.1 실행 시간과 결과 저장 데코레이터 만들기
다음은 함수의 실행 시간과 결과를 저장하는 데코레이터를 작성해 보세요.
import time
class TimeLogger:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
start_time = time.time()
result = self.func(*args, **kwargs)
end_time = time.time()
duration = end_time - start_time
print(f"{self.func.__name__} 실행 시간: {duration:.2f} 초")
return result
@TimeLogger
def complex_task():
time.sleep(1)
return "작업 결과"
output = complex_task()
print("결과:", output)
5.2 사용자 입력 검증 데코레이터 작성하기
아래 데코레이터는 사용자로부터 입력받은 값이 양수인지 확인하는 역할을 합니다. 입력이 양수가 아니면 경고 메시지를 출력합니다.
def positive_input_validator(func):
def wrapper(number):
if number < 0:
print("경고: 양수를
입력해야 합니다.")
return
return func(number)
return wrapper
@positive_input_validator
def display_number(number):
print("입력된 숫자:", number)
display_number(10) # 정상 출력
display_number(-5) # 경고 출력
요약
데코레이터는 Python 코드의 가독성과 효율성을 크게 높이는 유용한 기능입니다. 데코레이터로 중복 작업을 줄이고, 클래스 데코레이터를 통해 상태를 관리하는 다양한 활용을 익혀보세요. 실무에서도 여러 번 사용하게 될 강력한 도구입니다.
디스크립션: Python 데코레이터는 코드 재사용과 확장성을 높이는 필수 도구입니다. 함수형과 클래스형 데코레이터를 실습하며, 데코레이터 활용법을 초보자도 쉽게 익혀보세요.