فصل دوم: دکوراتورها

دکوراتور با آرگومان و functools.wraps

دکوراتورهای پارامتری و حفظ متادیتای تابع

گاهی لازم است خود دکوراتور نیز آرگومان بگیرد؛ برای مثال دکوراتوری که تعداد دفعات تکرار یک تابع را مشخص می‌کند. برای این کار به یک لایه‌ی اضافه‌ی تودرتو نیاز داریم.

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 این متادیتا را از تابع اصلی حفظ می‌کند و استفاده از آن در هر دکوراتور حرفه‌ای یک قاعده‌ی استاندارد است.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.