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

[PYTHON] 인자를 가진 데코레이터(Decorator)의 3중 중첩 구조 구현 방법과 2가지 핵심 차이 해결

by Papa Martino V 2026. 3. 1.
728x90

데코레이터 (Decorator)
데코레이터 (Decorator)

 

파이썬의 데코레이터(Decorator)는 코드의 재사용성과 가독성을 극대화하는 강력한 도구입니다. 하지만 일반적인 데코레이터를 넘어, 데코레이터 자체에 인자(Argument)를 전달해야 하는 상황에 직면하면 많은 개발자가 혼란을 겪습니다. 왜 인자가 있는 데코레이터는 일반 데코레이터와 달리 '3중 중첩 구조'를 가져야만 할까요? 본 포스팅에서는 인터프리터의 동작 원리를 바탕으로 인자 있는 데코레이터의 설계 방법과 내부 메커니즘을 심층 분석합니다.


1. 일반 데코레이터 vs 인자 있는 데코레이터의 구조적 차이

일반적인 데코레이터는 함수를 인자로 받아 새로운 함수를 반환하는 2중 중첩 구조입니다. 반면, 인자를 받는 데코레이터는 인자를 먼저 처리하고, 그 결과로 실제 데코레이터 함수를 반환해야 하므로 한 단계 더 깊은 스코프가 필요합니다.

[비교] 데코레이터 유형별 호출 메커니즘 차이

항목 일반 데코레이터 (Basic) 인자 있는 데코레이터 (Parameterized)
중첩 레벨 2중 중첩 (Wrapper 내포) 3중 중첩 (Decorator Factory 포함)
작동 원리 decorator(func) decorator(args)(func)
반환값 래퍼 함수 (Wrapper) 데코레이터 함수 그 자체
주요 용도 단순 로깅, 실행 시간 측정 권한 설정, 반복 횟수 지정, 환경별 옵션 부여

2. 3중 중첩 구조의 단계별 역할 해결

인자를 가진 데코레이터를 구현할 때는 '데코레이터 팩토리' 패턴을 따르게 됩니다. 각 계층의 역할은 다음과 같습니다.

  1. 최외곽 함수 (Decorator Factory): 데코레이터에 전달될 '인자'를 받아 클로저(Closure)에 저장합니다.
  2. 중간 함수 (Actual Decorator): 우리가 흔히 아는 데코레이터의 본체입니다. 대상 함수(func)를 인자로 받습니다.
  3. 최내곽 함수 (Wrapper): 대상 함수를 실제로 감싸고, 실행 전후의 로직을 처리하며 최종적으로 실행 결과를 반환합니다.

3. Sample Example: 반복 실행 데코레이터 구현

특정 함수를 지정된 횟수만큼 반복 실행하도록 하는 데코레이터를 통해 3중 구조의 실체를 확인해 보겠습니다.


import functools

def repeat(count):
    """1단계: 인자를 받는 데코레이터 팩토리"""
    def decorator_repeat(func):
        """2단계: 실제 함수를 인자로 받는 데코레이터"""
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            """3단계: 실제 로직을 수행하는 래퍼 함수"""
            result = None
            for i in range(count):
                print(f"[{i+1}/{count}] {func.__name__} 실행 중...")
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator_repeat

# 사용 예시 (인자 3을 전달)
@repeat(count=3)
def greet(name):
    print(f"안녕하세요, {name}님!")

greet("채원")

동작 원리 분석

위 코드에서 @repeat(count=3)이 호출되면, 먼저 repeat(3)이 실행되어 decorator_repeat 함수를 반환합니다. 이후 인터프리터는 decorator_repeat(greet)를 호출하여 최종적으로 wrappergreet라는 이름에 바인딩합니다. 이 과정에서 count 값은 클로저 덕분에 wrapper 내부에서 계속 유지됩니다.


4. 전문적인 지식: functools.wraps의 중요성

3중 중첩 구조에서 가장 흔히 발생하는 문제는 원본 함수의 메타데이터(이름, 독스트링 등)가 소실되는 것입니다. 래퍼 함수가 원본 함수를 대체하기 때문인데, 이를 해결하기 위해 @functools.wraps(func)를 반드시 사용해야 합니다. 이는 디버깅 환경에서 스택 트레이스를 정확히 유지하고, help() 함수 호출 시 원본 정보를 보여주도록 보장하는 전문 개발자의 필수 습관입니다.


5. 고급 활용: 유연한 데코레이터 설계 방법

최근에는 인자가 있을 수도 있고 없을 수도 있는 유연한 데코레이터를 설계하는 기법도 많이 쓰입니다. 이는 팩토리 함수 내부에서 첫 번째 인자가 함수인지 아닌지를 판단하여 2중과 3중 구조를 동적으로 전환하는 방식으로 구현됩니다. 이러한 유연성은 프레임워크 설계 시 사용자 경험을 대폭 향상시킵니다.


6. 결론: 계층적 스코프 이해의 핵심

인자 있는 데코레이터의 3중 중첩 구조는 파이썬의 '일급 객체 함수'와 '클로저' 개념의 결정체입니다. 계층별 역할을 명확히 구분하면 복잡한 비즈니스 로직을 비침투적으로(Non-intrusive) 기존 코드에 주입할 수 있습니다. 3단계의 흐름을 완벽히 이해함으로써 더 높은 수준의 추상화와 깔끔한 코드 구조를 지향해 보시기 바랍니다.


내용의 출처 및 공신력 있는 자료

  • Python Official Docs - "Glossary: decorator" & "functools.wraps"
  • "Effective Python: 90 Specific Ways to Write Better Python" by Brett Slatkin
  • Python Enhancement Proposals (PEP) 318 - Decorators for Functions and Methods
  • Real Python - "Primer on Python Decorators: Decorators With Arguments"
728x90