
개요
파이썬 실력을 한 단계 높이기 위해서는 단순히 문법을 아는 것을 넘어, 코드의 효율성과 가독성을 극대화하는 도구들을 이해해야 한다. 그 중심에 있는 것이 바로 데코레이터(Decorator)와 제너레이터(Generator)이다. 이들은 중복 코드를 제거하고 복잡한 로직을 추상화하여 유지보수가 쉬운 코드를 만들어준다. 본 포스팅에서는 이 두 기능의 작동 원리를 파헤치고, 실무에서 왜 이 기술들을 선택해야 하는지 상세히 정리한다.
1. 함수를 감싸는 마법: 데코레이터(Decorator)
데코레이터는 기존 함수의 코드를 수정하지 않고도 앞뒤에 새로운 기능을 추가할 수 있게 해주는 도구이다. 파이썬은 이를 더 간결하게 표현하기 위해 Syntax Sugar를 제공한다.
Syntax Sugar란?
프로그래밍 언어에서 코드를 좀 더 간결하고 읽기 쉽게 만들기 위해 제공되는 문법적 기능이다. 내부 동작은 동일하지만 사람이 읽기에 직관적인 형태를 제공한다.
작동 원리 파헤치기
데코레이터의 Syntax Sugar인 '@' 기호를 사용하면, 파이썬 내부에서는 다음과 같은 일이 일어난다.
import time
def timer_decorator(func):
# 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:.4f}초이다.")
return result
return wrapper
# @timer_decorator -> decorator 설정
@timer_decorator
def heavy_processing():
time.sleep(1)
print("처리가 완료되었다.")
heavy_processing()

- 함수 전달: 내부적으로 'heavy_processing = timer_decorator(heavy_processing)'와 동일하게 처리된다.
- wrapper의 역할: 원래 함수를 감싸는 대리인 역할을 수행하며, 부가 로직(시간 측정 등)을 핵심 로직 전후에 실행한다.
2. 필요한 만큼만 생성한다: 제너레이터(Generator)
제너레이터는 데이터를 한꺼번에 메모리에 올리는 리스트와 달리, 데이터가 필요할 때마다 하나씩 '생성'하거나 '선별'하여 전달하는 특별한 함수이다.
yield의 정체
제너레이터 함수는 'return' 대신 'yield' 키워드를 사용한다.
def get_number_generator(n):
for i in range(n):
yield i # 여기서 i를 반환하고, 함수의 상태를 유지한 채 멈춘다. (생성 및 일시정지)
# 다음 호출 시 이 지점 바로 다음부터 다시 실행된다.
gen = get_number_generator(3)
print(next(gen)) # 0 반환 후 정지
print(next(gen)) # 1 반환 후 정지

3. 실무에서 왜 쓰는가? (기술적 설득력)
단순히 "리스트를 써도 되지 않나?"라는 의문에 대해, 데코레이터와 제너레이터는 '단일 책임 원칙'과 '클린 코드' 관점에서 해답을 제시한다.
3.1. 데코레이터: 단일 책임 원칙(SRP)의 실현
클래스의 핵심 기능과 부가 기능(시간 측정, 로깅 등)을 분리할 때 데코레이터는 최상의 도구가 된다.
import time
def timer_decorator(func):
# 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:.4f}초이다.")
return result
return wrapper
class Display:
"""화면 출력을 담당하는 클래스"""
# @timer_decorator -> decorator 설정 (출력 기능과 시간 측정 책임의 분리)
@timer_decorator
def print_message(self, message):
time.sleep(0.5)
print(f"메시지: {message}")
display = Display()
display.print_message("파이썬 중급 강좌를 시작한다.")

- 책임 분리: 'Display' 클래스는 출력에만 집중하고, 시간 측정은 데코레이터가 전담하여 SRP를 준수한다.
3.2. 제너레이터: 데이터 필터링의 추상화와 가독성
제너레이터는 단순히 데이터를 만드는 도구가 아니라, 복잡한 '데이터 선별 로직(Filtering)'을 함수 내부로 숨겨서 사용자에게 깨끗한 데이터 흐름만을 전달하는 추상화 도구이다.
로직의 분리와 유지보수 단일화
단순한 필터링은 한 줄의 'if' 문으로 충분하지만, 수식이 복잡해지면 메인 로직을 해치게 된다. 제너레이터는 이 수식을 '가두는' 역할을 한다.
# [나쁜 예시] 복잡한 필터링 수식이 메인 로직(for 루프)에 노출되어 가독성을 해침
for item in raw_data:
if (item.status == 'active' and item.price > 100 and not item.is_expired):
print(f"핵심 처리: {item}")
# [좋은 예시] 필터링 로직을 제너레이터로 추상화하여 의도만 드러냄
def active_premium_stream(data):
"""복잡한 수식을 이 안에 가둬서 사용하는 쪽의 코드를 깨끗하게 유지한다."""
for item in data:
if (item.status == 'active' and item.price > 100 and not item.is_expired):
yield item
# 사용자는 '어떤 조건'인지 몰라도 '유효한 프리미엄 데이터'임에 집중할 수 있다.
for item in active_premium_stream(raw_data):
print(f"핵심 처리: {item}")
- 가독성 향상: 메인 루프에서 지저분한 수식을 제거하고 비즈니스 로직에만 집중하게 한다.
- 변경의 최소화: 필터링 조건이 변경되어도 제너레이터 함수 한 곳만 수정하면 이를 사용하는 모든 코드가 안전하게 업데이트된다.
- 메모리 낭비 방지: 여러 단계의 데이터 처리 파이프라인에서 불필요한 중간 리스트 생성을 막아 비효율적인 메모리 복사를 방지한다.
Conclusion
데코레이터는 코드의 중복을 제거하고 책임을 분리하며, 제너레이터는 복잡한 필터링 로직을 추상화하여 가독성과 유지보수성을 확보한다. 파이썬의 유연함을 실무적인 안정성으로 승화시키는 것이 이 두 도구의 핵심이다.
오늘 학습한 로직의 추상화와 가독성 향상의 철학을 프로젝트에 녹여내어,
성능과 유지보수성을 모두 잡는 개발자가되어보자
'Dev > Python' 카테고리의 다른 글
| 파이썬 중급: 이터러블(Iterable)과 이터레이터(Iterator) 정리 (0) | 2026.01.18 |
|---|---|
| 파이썬 중급: 컨텍스트 매니저와 with 구문 완벽 이해하기 (0) | 2026.01.17 |
| 파이썬 중급: 클래스 정의부터 파이썬다운 객체지향 특징까지 완벽 정리 (0) | 2026.01.15 |
| 파이썬 기초: 파일 입출력 완벽 가이드 (기초부터 JSON 활용까지) (0) | 2026.01.14 |
| 파이썬 기초: 표준 라이브러리(Standard Library) 활용하기 (0) | 2026.01.13 |