دکوراتورهای پارامتری و حفظ متادیتای تابع
گاهی لازم است خود دکوراتور نیز آرگومان بگیرد؛ برای مثال دکوراتوری که تعداد دفعات تکرار یک تابع را مشخص میکند. برای این کار به یک لایهی اضافهی تودرتو نیاز داریم.
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"سلام {name}")
greet("نیما")در این ساختار سهلایه، repeat آرگومان میگیرد و decorator واقعی را میسازد که خودش تابع اصلی را میگیرد. این الگو ممکن است در ابتدا گیجکننده باشد، اما با تمرین کاملاً قابل درک میشود.
نکتهی بسیار مهم استفاده از @wraps(func) از ماژول functools است. بدون آن، پس از اعمال دکوراتور، ویژگیهای تابع اصلی مانند __name__ و مستندات آن (docstring) با ویژگیهای تابع wrapper جایگزین میشوند که دیباگ کردن برنامه را دشوار میکند. wraps این متادیتا را از تابع اصلی حفظ میکند و استفاده از آن در هر دکوراتور حرفهای یک قاعدهی استاندارد است.