728x90
데코레이터란 자신이 감싸고 있는 함수가 호출되기 전과 후에 코드를 추가로 실행해주는 기능
인자값과 반환값을 출력하는 데코레이터 예시
def trace(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):
"""Return n 번째 피보나치 수"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n - 1))
fibonacci(4)
print(fibonacci)
출력결과
- 아래와 같이
wrapper
에 관한 정보도 있다.- trace 함수 본문에 정의된
wrapper
함수를 반환하기 때문에 표기된다. - 데코레이터에 인해 이
wrapper
함수가 모듈에fibonacci
라는 이름으로 등록된다.
- trace 함수 본문에 정의된
fibonacci(0, {}) -> 0
fibonacci(1, {}) -> 1
fibonacci(2, {}) -> 1
fibonacci(1, {}) -> 1
fibonacci(0, {}) -> 0
fibonacci(2, {}) -> 1
fibonacci(3, {}) -> 2
fibonacci(4, {}) -> 3
...
<function trace.<locals>.wrapper at 0x...>
인트로스펙션에서의 문제
help
내장 함수를 호출하면fibonacci
맨 앞에 있는 독스트링이 출력되어야 하지만 출력되지 않는다.- 데코레이터가 감싸고 있는 원래 함수의 위치를 찾을 수없기 때문에 객체 직렬화도 깨진다.
- 메타데이터가
wrapper
함수로 대체되었기 떄문이다.
- 아래는 객체를 직렬화시키는 코드인데, 직렬화에 실패하는 에러가 발생한다.
import pickle
pickle.dumps(fibonacci)
wraps 를 통한 메타데이터 이슈 해결
@wraps
를 사용하면 데코레이터 내부에 들어가는 함수에서 중요한 메타데이터를 복사해 wrapper 함수에 적용해준다.
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):
"""Return n 번째 피보나치 수"""
if n in (0, 1):
return n
return (fibonacci(n - 2) + fibonacci(n - 1))
help(fibonacci)
import pickle
print(pickle.dumps(fibonacci))
728x90
'Programming Language > Python' 카테고리의 다른 글
BETTER WAY 31 - 인자에 대해 이터레이션할 때는 방어적이 돼라 (0) | 2024.12.03 |
---|---|
BETTER WAY 30 - 리스트를 반환하기보다는 제너레이터를 사용하라 (0) | 2024.12.02 |
BETTER WAY 21 - 변수 영역과 클로저의 상호작용 방식을 이해하라 (0) | 2024.11.25 |
BETTER WAY 15 - 딕셔너리 삽입 순서에 의존할 떄는 조심하라 (2) | 2024.11.11 |
BETTER WAY 14 - 복잡한 기준을 사용해 정렬할 때는 key 파라미터를 사용하라 (0) | 2024.10.14 |