기본 데코레이터는 「def deco(func)」 형식이지만, 더 정교한 패턴은 「인자를 받는 데코레이터」와 「함수 정보를 보존하는 wraps」입니다.
인자가 있는 데코레이터.
def repeat(n): def decorator(func): def wrapper(*args, **kwargs): for _ in range(n): func(*args, **kwargs); return wrapper; return decorator.
@repeat(3); def hello(): print("안녕").
hello() — "안녕"이 3번 출력.
「세 겹 함수」 — 인자 받기, 함수 받기, 호출 처리.
functools.wraps.
데코레이터는 함수를 wrapper로 감싸는데, 이 과정에서 원본 함수의 __name__, __doc__, 시그니처가 wrapper의 것으로 바뀌어 버립니다.
wraps는 이 정보를 보존해 줍니다.
from functools import wraps.
def deco(func): @wraps(func); def wrapper(*args, **kwargs): return func(*args, **kwargs); return wrapper.
wraps가 없으면 help(decorated_func), decorated_func.__name__이 wrapper의 정보로 보여 디버깅·문서화에 혼란이 생깁니다.
wraps 한 줄로 모든 게 해결되니, 데코레이터를 만들 때는 거의 항상 함께 써야 합니다.
복잡한 데코레이터의 흔한 패턴은 인자 + wraps의 결합입니다.
def cache(seconds): def decorator(func): @wraps(func); def wrapper(*args, **kwargs): ...; return wrapper; return decorator.
@cache(seconds=60)으로 사용.
이 패턴이 친숙해지면 Flask·Django·FastAPI의 다양한 데코레이터를 자연스럽게 읽을 수 있습니다.
한 줄 요약
인자가 있는 데코레이터는 「세 겹 함수」 구조이고, functools.wraps는 데코레이터가 원본 함수의 이름·docstring을 보존하게 합니다.
둘 다 데코레이터 작성의 표준입니다.
더 알아볼 것
- 데코레이터 체이닝 — 여러 데코레이터 결합
- 파라미터 검증 데코레이터 만들기
- contextlib.contextmanager — 컨텍스트 매니저 데코레이터