#ex) 함수가 호출될 때마다 인자 값과 반환 값을 출력하고 싶다고 하자.
# 이런 기능은 재귀적 함수에서
#함수 호출이 재귀적으로 내포되는 경우 디버깅할 때 특히 유용하다.
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))
@ 기호를 사용하는 것은 이 함수에 대해 데코레이터를 호출한 후, 데코레이터가 반환한 결과*를 원래 함수가 속해야 하는 영역에 원래 함수와 같은 이름으로 등록하는 것과 같다.
#wrapper의 코드를 원래의 fibonacci함수가 실행되기 전과 후에 실행한다.
# wrapper는 재귀 스택의 매 단계마다 함수의 인자와 반환 값을 출력한다.
fibonacci = trace(fibonacci)
fibonacci(4)
fibonacci((0,), {}) -> 0
wrapper((0,), {}) -> 0
wrapper((0,), {}) -> 0
fibonacci((1,), {}) -> 1
wrapper((1,), {}) -> 1
wrapper((1,), {}) -> 1
fibonacci((2,), {}) -> 1
wrapper((2,), {}) -> 1
wrapper((2,), {}) -> 1
fibonacci((1,), {}) -> 1
wrapper((1,), {}) -> 1
wrapper((1,), {}) -> 1
fibonacci((0,), {}) -> 0
wrapper((0,), {}) -> 0
wrapper((0,), {}) -> 0
fibonacci((1,), {}) -> 1
wrapper((1,), {}) -> 1
wrapper((1,), {}) -> 1
fibonacci((2,), {}) -> 1
wrapper((2,), {}) -> 1
wrapper((2,), {}) -> 1
fibonacci((3,), {}) -> 2
wrapper((3,), {}) -> 2
wrapper((3,), {}) -> 2
fibonacci((4,), {}) -> 3
wrapper((4,), {}) -> 3
wrapper((4,), {}) -> 3
3
def decorator(n):
def outer(func):
def deco_func():
for i in range(n):
print("tistory")
func()
return deco_func
return outer
def function1():
print("ssungkang")
#기존엔 변수에 함수를 쓰워줬다.
decorator_3 = decorator(3)
function1 = decorator_3(function1)
function1()
tistory
tistory
tistory
ssungkang
def decorator(n):
def outer(func):
def deco_func():
for i in range(n):
print("tistory")
func()
return deco_func
return outer
@decorator(3)
def function1():
print("ssungkang")
#안에 종속하게할 함수위에 @를 이용하여 적용해주면 된다.
function1()
tistory
tistory
tistory
ssungkang
print(fibonacci)
<function trace..wrapper at 0x0000013F5F284048>
# 예를들면 꾸며진 fibonacci함수에 help 내장 함수를 호출하면 쓸모가 없다.
# fibonacci 함수의 맨 앞부분에 있는 독스트링이 출력돼야 하지만, 실제론 아니다,
help(fibonacci)
Help on function wrapper in module main:
wrapper(*args, **kwargs)
#데코레이터가 감싸고 있는 원래 함수의 위치를 찾을 수 없기 때문에 객체직렬화도 깨진다.
import pickle
print(pickle.dumps(fibonacci))
AttributeError Traceback (most recent call last)
in
2
3 import pickle
----> 4 print(pickle.dumps(fibonacci))
AttributeError: Can't pickle local object 'trace..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))
Help on function fibonacci in module main:
fibonacci(n)
Return n 번째 피보나치 수
b'\x80\x03cmain\nfibonacci\nq\x00.'