AzLearn

المُزخرفات

Decorators

مفهوم ~22 دقيقة

المُزخرفات — Decorators

المُزخرفات هي واحدة من أكثر أدوات Python قوةً وأناقةً. تجدها في كل مكتبة Python ناضجة — Flask يستخدمها لتعريف المسارات (@app.route), Django لصلاحيات المستخدم (@login_required), وdataclasses نفسها مُزخرف. فهمها يفتح لك باباً لكتابة كود أكثر نظافة وأقل تكراراً.

الدوال كقيم من الدرجة الأولى

قبل أن نتحدث عن المُزخرفات، يجب أن تفهم مبدأً أساسياً في Python: الدوال قيم مثل الأعداد والنصوص. يمكن تمريرها كمعاملات، تخزينها في متغيرات، وإرجاعها من دوال أخرى.

main.go

الدالة make_multiplier تُنشئ دالة جديدة في كل استدعاء وتُرجعها. هذه الدالة الداخلية تتذكر قيمة factor حتى بعد خروج make_multiplier — هذا يسمى Closure (إغلاق).

مُزخرف بسيط — Simple Decorator

المُزخرف في جوهره هو دالة تأخذ دالة وتُرجع دالة. تُضيف سلوكاً قبل أو بعد الدالة الأصلية دون تعديلها.

main.go

*args و**kwargs تجعل wrapper مرنة — تقبل أي عدد من المعاملات وأي معاملات مسماة، وتُمررها للدالة الأصلية كما هي.

صياغة @ — The @ Syntax

Python توفر صياغة مختصرة باستخدام @ تجعل الكود أكثر وضوحاً. ما فعلناه يدوياً (add = log_call(add)) يعادل تماماً:

main.go

@log_call قبل تعريف greet يعادل كتابة greet = log_call(greet) بعد التعريف. الصياغة بـ@ أكثر وضوحاً لأن المُزخرف يظهر مع تعريف الدالة مباشرةً.

مُزخرف مع معاملات — Decorator Factory

أحياناً تريد مُزخرفاً قابلاً للإعداد — مثل @retry(times=3) أو @cache(ttl=60). هنا تحتاج decorator factory: دالة تُنتج مُزخرفاً.

main.go

لاحظ الطبقات الثلاث:

  • repeat(times) — تأخذ الإعداد وتُرجع مُزخرفاً
  • decorator(fn) — المُزخرف الفعلي، يأخذ الدالة ويُرجع wrapper
  • wrapper(*args, **kwargs) — الدالة المُعدَّلة الفعلية

@repeat(times=3) يعادل: أولاً يستدعي repeat(3) للحصول على مُزخرف، ثم يُطبّق ذلك المُزخرف على say.

functools.wraps — حفظ البيانات الوصفية

مشكلة صامتة تحدث مع المُزخرفات: wrapper تحلّ محل الدالة الأصلية، فتضيع اسمها ووثائقها.

main.go

functools.wraps ضروري في أي مُزخرف تكتبه. بدونه يفشل help() ويتعطّل inspect، وتختفي وثائقك.

مُزخرفات متعددة — Stacking Decorators

يمكن تطبيق أكثر من مُزخرف على دالة واحدة. تُطبَّق من الأقرب للدالة إلى الأبعد (من الأسفل للأعلى):

main.go

مُزخرف عملي — Timing Decorator

main.go

متى تستخدم المُزخرفات؟

المُزخرفات مناسبة عندما يكون لديك سلوك متكرر ينطبق على دوال متعددة، ومستقل عن منطقها الرئيسي. أمثلة شائعة:

  • Logging — تسجيل كل استدعاء ومعاملاته
  • Timing — قياس الأداء
  • Caching — حفظ النتائج لتجنب إعادة الحساب (functools.lru_cache)
  • Auth — التحقق من صلاحية المستخدم قبل تنفيذ الدالة
  • Retry — إعادة المحاولة عند الفشل (ما ستبنيه في الدرس الأخير)
تحدي — Challenge