#!/usr/bin/env python # coding: utf-8 # # 26. functools.wrap을 사용해 함수 데코레이터를 정의하라 # 파이썬은 함수에 적용할 수 있는 데코레이터를 정의하는 특별한 구문을 제공한다. # # 데코레이터는 자신이 감싸고 있는 함수가 호출되기 전과 후에 코드를 추가로 실행해준다. # # 이는 데코레이터가 자신이 감싸고 있는 함수의 입력 인자, 반환값, 함수에서 발생한 오류에 접근할 수 있다는 뜻이다. # In[14]: 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 # 이 데코레이터를 함수에 적용할 떄는 @ 기호를 사용한다. # In[18]: @trace def fibonacci(n): """n번쨰 피보나치 수를 반환한다.""" if n in (0, 1): return n return (fibonacci(n - 2) + fibonacci(n - 1)) # In[19]: fibonacci(4) # In[20]: fibonacci = trace(fibonacci) # In[21]: fibonacci(4) # In[22]: print(fibonacci) # In[23]: help(fibonacci) # In[24]: import pickle pickle.dumps(fibonacci) # 문제를 해결하는 방법은 functools 내장 모듈에 정의된 waps 도우미 함수를 사용하는 것이다. # In[25]: 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 # In[26]: @trace def fibonacci(n): """n번쨰 피보나치 수를 반환한다.""" if n in (0, 1): return n return (fibonacci(n - 2) + fibonacci(n - 1)) # In[27]: help(fibonacci) # 하지만 키워드 인자와 디폴트 값은 예상대로 잘 작동한다. # In[28]: import pickle pickle.dumps(fibonacci) # ## 기억해야 할 내용 # - 파이썬 데코레이터는 실행 시점에 함수가 다른 함수를 변경할 수 있게 해주는 구문이다. # - 데코레이터를 사용하면 디버거 등 인트로스펙션을 사용하는 도구가 잘못 작동할 수 있다. # - 직접 데코레이터를 구현할 때 인트로스펙션에서 문제가 생기지 않길 바란다면 functools 내장 모듈의 wraps 데코레이터를 사용하라.