Python의 Decorator 패턴

Alpha, Orderly·2025년 8월 8일
0

Python

목록 보기
3/3

데코레이터 패턴

  • 기존 코드를 수정하지 않고 동적으로 기능을 확장할수 있게 해주는 패턴
  • 함수를 인자로 받아 감싼 뒤, 새로운 함수를 반환하는 함수로 구현한다.

왜?

  • 코드의 쉬운 재사용
  • 관심사의 분리
  • 쉬운 기능 확장

예시

def logger(func):
	# arg, kwargs는 func에 전달되는 패러미터 들이다.
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}...")
        result = func(*args, **kwargs)
        print(f"{func.__name__} finished.")
        return result
    return wrapper

@logger
def say_hello():
    print("Hello!")

say_hello()

1. 인자를 받지 않는 데코레이터

import time

def timeit(func):
    def wrapper(*args, **kwargs):
        current = time.time()
        result = func(*args, **kwargs)
        after = time.time()

        print(f'{after - current} second took')

        return result

    return wrapper

@timeit
def test1():
    ans = 0
    for i in range(100000000):
        ans += i
    print(ans % 10**9)

test1()

2. 인자를 받는 데코레이터

def repeat(n: int):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)

        return wrapper
    return decorator

@repeat(3)
def greet():
    print('Hello World!')

greet()
  • 최상단에 인자를 받는 부분을 포함하여 nesting 한다.

클래스 기반 데코레이터

class RequireRole:
    def __init__(self, role):
        self.role = role  # 데코레이터가 사용할 상태 (예: 권한)

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            user = kwargs.get("user") or (args[0] if args else None)
            if user != self.role:
                print(f"Access denied, need to be {self.role}")
                return
            return func(*args, **kwargs)
        return wrapper
        
@RequireRole("admin")
def delete_database(user):
    print(f"{user} deleted the DB")
  • __init__ 에서 직접 parameter를 받을수 있다.
  • 데코레이터의 구현은 __call__에서 한다.

데코레이터에서 받아올수 있는 기타 정보들

속성설명
__name__함수 이름
__doc__함수 설명 문자열
__module__함수가 정의된 모듈 이름
__annotations__타입 힌트
__defaults__기본 인자 값
functools.wraps위 정보들을 감싸는 wrapper에 그대로 복사
def logger(func):
    def wrapper(*args, **kwargs):
        print(f"Function: {func.__name__}")
        print(f"Module: {func.__module__}")
        print(f"Doc: {func.__doc__}")
        return func(*args, **kwargs)
    return wrapper

@logger
def greet(name: str = "world"):
    """Prints a greeting"""
    print(f"Hello, {name}!")
profile
만능 컴덕후 겸 번지 팬

0개의 댓글