파이썬은 함수에 적용할 수 있는 데코레이터를 정의하는 특별한 구문을 제공
예시) 함수가 호출될 때마다 인자 값과 반환 값을 출력하고 싶음
*args
와 **kwargs
를 사용해 감싸진 함수의 모든 파라미터를 전달받음
def trace(func):
def wrapper(*args, **kwargs): # 위치기반인자(스타인자), 모든 키워드 인자를 dict로 받음
result = func(*args, **kwargs)
print(f'{func.__name__}({args!r}, {kwargs!r}) '
f'-> {result!r}')
return result
return wrapper
# 위 데코레이터 함수를 적용할 때는 @ 기호 사용함
@trace
def fibonacci(n):
"""n번째 피보니치 수를 반환한다"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n - 1))
@ 기호를 사용하는 것은 이 함수에 대해 데코레이터를 호출 후, 데코레이터가 반환한 결과를 원래 함수가 속해야 하는 영역에 원래 함수와 같은 이름으로 등록하는 것과 같음(????)
fibonacci = trace(fibonacci)
이렇게 꾸면진 함수(새로운 fibonacci)는 wrapper의 코드를 원래의 fibonacci 함수가 실행되기 전과 후에 실행함
따라서 wrapper는 재귀 스택의 매 단계마다 함수의 인자와 반환 값을 출력
fibonacci((0,), {}) -> 0
fibonacci((1,), {}) -> 1
fibonacci((2,), {}) -> 1
fibonacci((1,), {}) -> 1
fibonacci((0,), {}) -> 0
fibonacci((1,), {}) -> 1
fibonacci((2,), {}) -> 1
fibonacci((3,), {}) -> 2
fibonacci((4,), {}) -> 3
데코레이터가 반환하는 함수(감싸진 fibonacci)의 이름이 fibonacci가 아니게 됨
print(fibonacci)
>>
<function trace.<locals>.wrapper at 0x1031d1940>
왜냐면, trace 함수는 자신의 본문에 정의된 wrapper 함수를 반환함
→ 데코레이터로 인해 이 wrapper 함수가 모듈에 fibonacci라는 이름으로 등록됨
문제를 해결하는 방법은 functools
내장 모듈에 정의된 wraps 도우미 함수를 사용하는 것
from functools import wraps
def trace(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f'{func.__name__}({args!r}, {kwargs!r}) '
f'-> {result!r}')
return result
return wrapper
@trace
def fibonacci(n):
...
wraps를 wrapper 함수에 적용하면 wraps가 데코레이터 내부에 들어가는 함수에서 중요한 메타데이터를 복사해 wrapper 함수에 적용해줌
→ help()
를 실행하면 데코레이터로 감싸진 함수에 대해서도 원하는 결과를 얻을 수 있음
from functools import wraps
def trace(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
print(f'{func.__name__}({args!r}, {kwargs!r}) '
f'-> {result!r}')
return result
return wrapper
@trace
def fibonacci(n):
"""n번째 피보나치 수를 반환함"""
if n in (0, 1):
return n
return fibonacci(n - 2) + fibonacci(n - 1)
help(fibonacci)
print(fibonacci)
>>
Help on function fibonacci in module __main__:
fibonacci(n)
n번째 피보나치 수를 반환함
<function fibonacci at 0x104d5d940>