안녕하세요! 지난 시간에는 메모리 효율적인 데이터 생성을 위한 제너레이터(Generator)와 yield 키워드에 대해 알아보았습니다. 이제 여러분은 대량의 데이터를 다룰 때 메모리 사용량을 최적화하는 방법을 이해하셨을 거예요!
이번 시간에는 파이썬의 또 다른 강력하고 우아한 고급 문법인 **데코레이터(Decorator)**에 대해 알아보겠습니다. 데코레이터는 기존 함수나 메서드의 코드를 직접 수정하지 않고도, 그 기능을 확장하거나 변경할 수 있게 해주는 특별한 문법입니다.
마치 선물 포장지처럼, 원래의 함수(선물)는 그대로 두고 겉에 추가적인 기능(포장지)을 덧씌우는 것과 같다고 생각하시면 됩니다. 데코레이터는 웹 프레임워크, 로깅, 성능 측정 등 다양한 분야에서 광범위하게 사용됩니다.
Part 1: 데코레이터(Decorator)란 무엇인가?
데코레이터는 다른 함수를 인자로 받아서 새로운 기능을 추가한 함수를 반환하는 **고차 함수(Higher-Order Function)**입니다. 파이썬에서는 @ (앳 사인) 문법을 사용하여 함수 정의 바로 위에 데코레이터를 적용합니다.
1. 데코레이터의 기본 개념
- 함수를 인자로 받음: 데코레이터는 꾸며질 함수(원본 함수)를 입력으로 받습니다.
- 새로운 함수 반환: 데코레이터는 원본 함수에 추가적인 기능을 덧붙인 새로운 함수를 반환합니다.
- 코드를 직접 수정하지 않음: 원본 함수의 소스 코드는 그대로 유지됩니다.
2. 데코레이터의 필요성
- 코드 중복 제거: 여러 함수에 걸쳐 반복되는 공통적인 기능(예: 로깅, 권한 확인, 시간 측정)을 데코레이터로 만들어 재사용할 수 있습니다.
- 가독성 향상: 함수의 핵심 로직과 부가적인 기능을 분리하여 코드를 더 깔끔하고 읽기 쉽게 만듭니다.
- 유지보수 용이: 부가 기능의 변경이 필요할 때, 데코레이터만 수정하면 해당 데코레이터를 사용하는 모든 함수에 일괄적으로 적용됩니다.
Part 2: 데코레이터 기본 사용법
가장 간단한 형태의 데코레이터를 만들어보고, 어떻게 적용되는지 살펴보겠습니다.
1. 데코레이터 정의 및 적용
# 파일 이름: basic_decorator.py
# 1. 데코레이터 함수 정의
def my_decorator(func): # func는 꾸며질 함수 (예: greet)
def wrapper(): # 원본 함수를 감싸는(wrap) 새로운 함수
print("--- 함수 시작 ---") # 추가 기능 (함수 실행 전)
func() # 원본 함수 실행
print("--- 함수 종료 ---") # 추가 기능 (함수 실행 후)
return wrapper # 새로운 함수 (wrapper) 반환
# 2. 데코레이터 적용
@my_decorator # greet 함수에 my_decorator를 적용
def greet():
print("안녕하세요!")
@my_decorator # say_hello 함수에도 my_decorator를 적용
def say_hello():
print("Hello there!")
print("--- greet 함수 호출 ---")
greet() # greet()를 호출하면 실제로는 wrapper()가 실행됨
print("\n--- say_hello 함수 호출 ---")
say_hello() # say_hello()를 호출하면 실제로는 wrapper()가 실행됨
- my_decorator는 greet 함수를 인자로 받아서, wrapper라는 새로운 함수를 정의합니다.
- wrapper 함수는 --- 함수 시작 ---을 출력하고, 원래 greet 함수를 실행한 다음, --- 함수 종료 ---를 출력합니다.
- @my_decorator 문법은 greet = my_decorator(greet)와 동일한 의미입니다. 즉, greet라는 이름이 my_decorator가 반환한 wrapper 함수를 가리키게 됩니다.
- 따라서 greet()를 호출하면 wrapper()가 실행되어 추가 기능과 함께 원래 greet의 내용이 출력됩니다.
[VS Code 터미널 출력]

2. 원본 함수의 매개변수 처리: *args, **kwargs 활용
원본 함수가 매개변수를 받는 경우, wrapper 함수도 이 매개변수들을 받아 원본 함수에 전달해야 합니다. 이때 *args와 **kwargs를 활용하면 어떤 매개변수를 가진 함수라도 데코레이터로 꾸밀 수 있습니다.
# 파일 이름: decorator_with_args_kwargs.py
def log_execution(func):
def wrapper(*args, **kwargs): # 원본 함수의 모든 매개변수를 받음
print(f"함수 '{func.__name__}' 실행 시작...")
# 원본 함수 실행 및 결과 저장
result = func(*args, **kwargs) # 받은 매개변수를 원본 함수에 전달
print(f"함수 '{func.__name__}' 실행 종료. 결과: {result}")
return result # 원본 함수의 결과를 반환
return wrapper
@log_execution
def add(a, b):
return a + b
@log_execution
def multiply(x, y, z):
return x * y * z
@log_execution
def greet_person(name, greeting="Hello"):
return f"{greeting}, {name}!"
print("--- add 함수 호출 ---")
sum_result = add(10, 5)
print(f"add(10, 5)의 최종 결과: {sum_result}")
print("\n--- multiply 함수 호출 ---")
prod_result = multiply(2, 3, 4)
print(f"multiply(2, 3, 4)의 최종 결과: {prod_result}")
print("\n--- greet_person 함수 호출 ---")
greeting_result = greet_person("Alice", greeting="Hi")
print(f"greet_person('Alice', greeting='Hi')의 최종 결과: {greeting_result}")
- wrapper(*args, **kwargs): 이 부분이 핵심입니다. *args는 모든 위치 인자를 튜플로, **kwargs는 모든 키워드 인자를 딕셔너리로 받아줍니다.
- func(*args, **kwargs): 이렇게 받은 인자들을 다시 원본 함수 func에 그대로 전달하여 실행합니다.
- return result: 원본 함수가 반환하는 값을 wrapper 함수도 그대로 반환해야 합니다.
[VS Code 터미널 출력]

Part 3: 데코레이터에 인자 전달하기
때로는 데코레이터 자체에도 추가적인 설정 값을 전달하고 싶을 때가 있습니다. 예를 들어, 로깅 데코레이터에서 로그 레벨을 지정하는 경우입니다. 이 경우 데코레이터를 만드는 함수를 한 번 더 감싸는 형태로 구현합니다.
# 파일 이름: decorator_with_params.py
def repeat(num_times): # 데코레이터에 인자를 전달받는 외부 함수
def decorator_repeat(func): # 실제 데코레이터 함수
def wrapper(*args, **kwargs):
for _ in range(num_times): # num_times 만큼 반복
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3) # 데코레이터에 인자 전달 (함수 호출처럼)
def greet(name):
print(f"안녕하세요, {name}님!")
@repeat(num_times=2)
def print_message(message):
print(message)
print("--- greet 함수 (3회 반복) ---")
greet("김파이")
print("\n--- print_message 함수 (2회 반복) ---")
print_message("반복되는 메시지!")
- repeat(num_times): 이 함수가 데코레이터의 '공장' 역할을 합니다. num_times 인자를 받아서 실제 데코레이터인 decorator_repeat 함수를 반환합니다.
- @repeat(num_times=3): 이 문법은 greet = repeat(num_times=3)(greet)와 동일합니다. 즉, repeat(3)이 반환한 decorator_repeat 함수가 다시 greet 함수를 꾸미는 데코레이터로 사용됩니다.
[VS Code 터미널 출력]

Part 4: 데코레이터의 활용 사례
데코레이터는 파이썬 코드에서 매우 흔하게 사용되며, 다음과 같은 다양한 상황에서 유용합니다.
- 로깅(Logging): 함수의 실행 전/후에 로그를 남기거나, 함수의 인자와 반환값을 기록. (위의 log_execution 예시)
- 권한 확인(Authentication/Authorization): 특정 함수를 실행하기 전에 사용자에게 필요한 권한이 있는지 확인. (예: 웹 프레임워크의 @login_required)
- 성능 측정(Performance Timing): 함수의 실행 시간을 측정하여 성능 병목 지점 파악.
- 캐싱(Caching): 함수의 결과를 캐시하여 동일한 인자로 다시 호출될 때 계산 없이 바로 캐시된 결과를 반환.
- 유효성 검사(Validation): 함수의 인자가 유효한지 사전에 검사.
- 트랜잭션 관리(Transaction Management): 데이터베이스 작업에서 트랜잭션 시작/커밋/롤백을 자동화.
마무리하며
이번 시간에는 파이썬의 강력한 고급 문법인 **데코레이터(Decorator)**에 대해 자세히 알아보았습니다.
- 데코레이터는 @ 문법을 사용하여 함수나 메서드의 기능을 직접 수정하지 않고도 확장하거나 변경할 수 있게 해주는 고차 함수입니다.
- wrapper 함수를 통해 원본 함수를 감싸고, *args, **kwargs를 사용하여 원본 함수의 매개변수를 처리합니다.
- 데코레이터 자체에 인자를 전달하려면 함수를 한 번 더 감싸는 중첩 함수 구조를 사용합니다.
데코레이터는 코드의 중복을 줄이고, 가독성을 높이며, 유지보수를 용이하게 하는 매우 유용한 도구입니다. 처음에는 개념이 어렵게 느껴질 수 있지만, 다양한 예제를 통해 익숙해지면 여러분의 파이썬 코딩 실력을 한 단계 더 끌어올릴 수 있을 것입니다.
다음 포스팅에서는 파이썬에서 여러 작업을 동시에 처리하여 프로그램의 효율성을 높이는 **멀티스레딩(Multithreading)**과 **멀티프로세싱(Multiprocessing)**의 개념에 대해 알아보겠습니다.
궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!
'Python' 카테고리의 다른 글
7-7. os 모듈과 pathlib 모듈 (0) | 2025.07.06 |
---|---|
7-5. 가상 환경(Virtual Environment)의 이해와 사용법 (0) | 2025.07.05 |
7-2. 제너레이터(Generator)와 yield 키워드 (0) | 2025.07.03 |
7-1. 리스트/딕셔너리 컴프리헨션 심화 (0) | 2025.07.02 |
6-7. 캡슐화와 접근 제한자 개념 (0) | 2025.07.02 |