[Python] decorator - 인자 받기, 중첩 사용, wraps 이해하기
2025.06.07 - [Python/입문] - [Python] decorator 사용법 - 함수 위에 @가 붙는 이유?
[Python] decorator 사용법 - 함수 위에 @가 붙는 이유?
파이썬 코드를 보다보면 함수위에 '@'기호가 붙어있는 걸 볼 수 있습니다.@somethingdef my_function(): pass해당 기능은 데코레이터(decorator) 문법입니다.데코레이터는 기존 함수를 수정하지 않고도 함수
dev-kjs1219.tistory.com
지난 포스팅에 이어서 decorator를 더 잘 사용할 수 있는 방법에 대해 정리해보았습니다.
- decorator에 매개변수를 전달하는 방법
- decorator를 중첩해서 사용하는 방법
- 원래 함수 정보 유지를 위한 functools.wraps 의 역할
1. 매개변수를 받는 decorator
decorator는 아래와 같은 형태로 사용됩니다.
@simple_decorator
def func():
...
하지만 decorator에도 매개변수를 넘겨주고 사용하고 싶을때는 아래와 같이 사용할 수 있습니다.
@simple_decorator(n=10)
def func():
...
위와 같이 사용할 수 있는 구현 예제는 아래와 같습니다.
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs) :
for i in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hello!")
greet()
#Hello!
#Hello!
#Hello!
이 예제는 데코레이터에 인자를 전달하는 방법을 보여줍니다.
repeat 함수는 n이라는 매개변수를 받아 내부에 데코레이터 함수를 생성하고,
그 데코레이터는 전달받은 함수를 n번 반복해서 실행합니다.
이처럼 데코레이터에 인자를 전달하려면
"데코레이터를 반환하는 함수를 한 번 더 감싸는 구조"로 작성해야 합니다.
그 결과 @repeat(3)은 greet() 함수를 3번 실행하게 됩니다.
2. decorator 중첩사용
import time
def logger(func):
def wrapper(*args, **kwargs):
print(f"[LOG] {func.__name__} 호출됨")
return func(*args, **kwargs)
return wrapper
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"[TIMER] 실행 시간: {end - start:.4f}초")
return result
return wrapper
@timer
@logger
def process():
print("작업 수행 중...")
process()
#[LOG] process 호출됨
#작업 수행 중...
#[TIMER] 실행 시간: 0.0000초
이 예제에서는 데코레이터를 두 개 중첩하여 사용하는 방법을 보여주고 있습니다.
@logger가 먼저 process() 함수를 감싸고, 그 결과를 @timer가 다시 한 번 감싸는 구조입니다.
따라서 process()를 호출하면,
- 먼저 logger가 로그를 출력하고
- 그 후 timer가 시간을 측정하며 실행 시간을 출력합니다.
여러 데코레이터를 적용할 경우, 데코레이터는 아래에서부터 위로 순차적으로 감싸진다는 점을 기억해야 합니다.
이 순서에 따라 실행 흐름이나 출력 결과가 달라질 수 있습니다.
3. functools.wraps로 함수 정보 유지
from functools import wraps
def deco(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@deco
def test():
"""테스트 함수입니다."""
pass
print(test.__name__) # test
print(test.__doc__) # 테스트 함수입니다.
데코레이터를 사용하면 __name__, __doc__ 등의 함수 정보가
감싸진 내부 함수(wrapper)로 덮여쓰기 되어 버립니다.
따라서 원래 함수 이름이나 주석(docstring)을 참조하려 할 때 문제가 발생합니다.
이 문제를 해결하기 위해 파이썬에서는 functools 모듈에서 제공하는
@wraps(func) 데코레이터를 함께 사용합니다.
@wraps(func)는 내부 wrapper 함수에 원래 함수의 메타 정보를 그대로 복사해 주는 역할을 합니다.
이렇게 하면 데코레이터를 적용한 후에도 함수의 이름이나 설명 등이 정상적으로 유지됩니다.