본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 데코레이터(@) 완벽 가이드 : 코드의 재사용성과 우아함을 극대화하는 법

by Papa Martino V 2026. 2. 14.
728x90

데코레이터(@)
데코레이터(@)

기존 코드를 건드리지 않고 기능을 확장하는 고급 설계 기법 - 데코레이터의 원리부터 실무 활용까지


1. 서론: 코드의 중복을 해결하는 우아한 방법

프로그래밍을 하다 보면 여러 함수에 공통적으로 적용해야 하는 로직이 생기기 마련입니다. 예를 들어, 함수의 실행 시간을 측정하거나, 사용자의 권한을 확인하거나, 로그를 남기는 작업 등이 그렇습니다. 모든 함수마다 동일한 코드를 복사해서 붙여넣는다면, 나중에 수정이 필요할 때 모든 곳을 찾아다녀야 하는 '관리의 지옥'에 빠지게 됩니다. 파이썬의 데코레이터(Decorator)는 바로 이러한 문제를 해결하기 위해 등장했습니다. 데코레이터는 단어 뜻 그대로 함수를 '장식'하는 도구입니다. 원본 함수의 코드를 전혀 수정하지 않으면서도, 그 함수가 실행되기 전후에 특별한 동작을 추가할 수 있게 해주는 파이썬의 핵심적인 고급 기능입니다.

2. 데코레이터의 근간: 일급 객체와 내부 함수

데코레이터를 제대로 이해하려면 파이썬의 두 가지 특징을 먼저 알아야 합니다.

  • 일급 객체(First-class Object): 파이썬에서 함수는 변수에 할당될 수 있고, 다른 함수의 인자로 전달될 수 있으며, 결과값으로 반환될 수도 있습니다.
  • 중첩 함수(Nested Function): 함수 내부에 또 다른 함수를 정의할 수 있으며, 내부 함수는 외부 함수의 변수에 접근할 수 있습니다.

이 두 가지 성질이 결합하여 "함수를 인자로 받아, 기능을 추가한 새로운 함수를 반환하는" 데코레이터의 구조가 완성됩니다.

3. 데코레이터 vs 일반 함수 호출 비교

기능을 확장할 때 데코레이터를 사용하는 방식과 일반적인 방식을 비교해 보겠습니다.

비교 항목 일반적인 함수 수정/호출 데코레이터(@) 활용
코드 수정 범위 원본 함수의 내부 코드를 직접 수정해야 함 원본 함수는 그대로 두고 선언부에 @만 추가
재사용성 함수마다 로직을 반복해서 작성해야 함 한 번 만든 데코레이터를 무한정 재사용 가능
가독성 핵심 로직과 부가 로직이 섞여 복잡함 함수의 본래 목적과 부가 기능이 명확히 분리됨
유지보수 수정 사항 발생 시 모든 함수를 찾아 수정 데코레이터 함수 하나만 수정하면 전체 적용

4. 실전 예제: 실행 시간 측정 데코레이터

가장 흔히 쓰이는 '함수 실행 시간 측정' 로직을 통해 데코레이터의 실체를 확인해 보겠습니다.

[Sample Example] 시간 측정 데코레이터 구현

import time

# 1. 데코레이터 함수 정의
def time_checker(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

# 2. 데코레이터 적용
@time_checker
def heavy_computation():
    """시간이 오래 걸리는 작업 시뮬레이션"""
    print("계산을 시작합니다...")
    time.sleep(2)
    print("계산 완료!")

# 3. 함수 실행
heavy_computation()

위 코드에서 @time_checker라는 문구 하나만으로 heavy_computation 함수는 실행 시간을 출력하는 강력한 기능을 갖게 되었습니다. 이것이 바로 파이썬 데코레이터의 힘입니다.

5. 데코레이터 사용 시 주의사항: wraps의 중요성

데코레이터를 사용하면 원본 함수가 wrapper 함수로 덮어씌워지기 때문에, 함수의 이름(__name__)이나 독스트링(__doc__) 같은 메타데이터가 사라지는 부작용이 있습니다. 이를 방지하기 위해 functools.wraps를 사용하는 것이 표준입니다.

from functools import wraps

def my_decorator(func):
    @wraps(func)  # 원본 함수의 메타데이터를 유지해줌
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

6. 결론: 언제 데코레이터를 써야 하는가?

데코레이터는 "횡단 관심사(Cross-cutting Concerns)"를 처리할 때 최고의 선택입니다. 로깅, 보안 인증, 캐싱, 데이터 유효성 검사 등 여러 함수에 공통적으로 들어가는 코드가 있다면 주저 없이 데코레이터를 설계해 보십시오. 코드의 양은 줄어들고, 논리는 더욱 선명해질 것입니다.

7. 내용 출처

  • Python Software Foundation - "Glossary: decorator"
  • PEP 318 - "Decorators for Functions and Methods"
  • Real Python - "Primer on Python Decorators"
  • Fluent Python by Luciano Ramalho - O'Reilly Media
728x90