Decorator có tham số cần ba tầng hàm: hàm ngoài nhận tham số cấu hình và trả về decorator, decorator nhận function và trả về wrapper.
python
import functools
import time
def retry(times=3, delay=0.5):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(times):
try:
return func(*args, **kwargs)
except ConnectionError:
if attempt == times - 1:
raise
time.sleep(delay)
return wrapper
return decorator
@retry(times=3)
def call_payment_api(order_id): ...@retry(times=3) được đọc là: gọi retry(times=3) trước, lấy kết quả rồi mới áp lên hàm.
functools.wraps để làm gì: không có nó, hàm sau khi decorate mang danh tính của wrapper — __name__ thành "wrapper", __doc__ mất, inspect.signature trả về (args, *kwargs). Điều này phá logging, sinh docs, và các framework đọc metadata (FastAPI đọc type hint, pytest đọc tên test). wraps copy __name__, __doc__, __module__, __qualname__, __dict__ và gắn __wrapped__ trỏ về hàm gốc.