Skip to content

Python:Decorator

파라미터 전달 가능한 데코레이터 만드는 방법

Python에서 파라미터를 전달할 수 있는 데코레이터를 만들 때, 일반적으로 세 가지 레벨의 함수가 필요합니다:

  1. 데코레이터 생성 함수
  2. 실제 데코레이터 함수
  3. 그리고 래핑된 함수입니다.

각 함수에 적절한 심볼명을 추천하면 다음과 같습니다:

def decorator_with_params(param1, param2):
    # 1. 데코레이터 생성 함수
    def decorator(func):
        # 2. 실제 데코레이터 함수
        def wrapper(*args, **kwargs):
            # 3. 래핑된 함수
            print(f"데코레이터 파라미터: {param1}, {param2}")
            print(f"함수 {func.__name__} 호출 전")
            result = func(*args, **kwargs)
            print(f"함수 {func.__name__} 호출 후")
            return result
        return wrapper
    return decorator

심볼명 추천 기준

  • 최상위 함수 (파라미터를 전달받는 생성 함수):
    • 이름: decorator_with_params, create_decorator, decorator_factory, param_decorator
    • 역할: 데코레이터의 동작 방식을 정의하는 파라미터를 받음.
  • 중간 함수 (데코레이터 함수):
    • 이름: decorator, inner_decorator, wrap_function
    • 역할: 데코레이터가 적용될 함수를 받아 내부에서 래핑 로직을 정의.
  • 내부 함수 (래퍼 함수):
    • 이름: wrapper, wrapped_func, decorated_func, inner_wrapper
    • 역할: 실제 함수를 호출하기 전/후에 추가 동작을 실행.
def param_decorator(param1, param2):
    def wrap_function(func):
        def inner_wrapper(*args, **kwargs):
            print(f"[DEBUG] Params: {param1}, {param2}")
            print(f"[DEBUG] Before calling {func.__name__}")
            result = func(*args, **kwargs)
            print(f"[DEBUG] After calling {func.__name__}")
            return result
        return inner_wrapper
    return wrap_function

# 데코레이터 사용
@param_decorator("Hello", "World")
def example_function(x, y):
    print(f"Running example_function with {x} and {y}")
    return x + y

# 함수 호출
result = example_function(10, 20)
print(f"Result: {result}")

Simple example

def measure_time(f):
    def wrap(*args):
        time1 = time.time()
        ret = f(*args)
        time2 = time.time()
        print('%s function took %0.6f s' % (f.__name__, (time2-time1)))
        return ret
    return wrap

# ...

@measure_time
def test(a):
    print('haha')

Decorators with Arguments

작동되는지 확인해봐야 한다.

def parametrized(dec):
    def layer(*args, **kwargs):
        def deco(f):
            return dec(f, *args, **kwargs)
        return deco
    return layer


@parametrized
def elapsed_time_debug(func, name, logger):
    def wrap(*args, **kwargs):
        s = time.time()
        func(*args, **kwargs)
        e = time.time()
        if logger:
            logger.debug("[{}] {} detect time: {}".format(name, func.__name__, e-s))
    return wrap

Documentation

functools 패키지의 의 wraps을 사용해야 한다.

from functools import wraps

# 파라메터 없는 데코레이터에도 @wraps 붙여주고
def decorator(func):
    @wraps(func)
    def decorator(*args, **kwargs):
        print("%s %s" % (func.__name__, "before"))
        result = func(*args, **kwargs)
        print("%s %s" % (func.__name__, "after"))
        return result
    return decorator


# 파라메터 있는 데코레이터에도 @wraps 붙여주고
def decorator_with_param(param):
    def wrapper(func):
        @wraps(func)
        def decorator(*args, **kwargs):
            print(param)
            print("%s %s" % (func.__name__, "before"))
            result = func(*args, **kwargs)
            print("%s %s" % (func.__name__ , "after"))
            return result
        return decorator
    return wrapper

See also

Favorite site

References


  1. SchoolofWeb_-_Python_Decorator.pdf