المولدات والمكررات
Generators & Iterators
المولدات والمكررات — Generators & Iterators
عندما تكتب for item in collection، Python تستخدم بروتوكول التكرار (Iteration Protocol) خلف الكواليس. فهم هذا البروتوكول يتيح لك بناء كائنات تتصرف مثل القوائم والتوبلات، لكنها أكثر كفاءةً في استخدام الذاكرة — لأنها تُنتج القيم واحدة بواحدة عند الطلب بدلاً من تحميل الكل في الذاكرة دفعة واحدة.
بروتوكول التكرار — Iteration Protocol
أي كائن قابل للتكرار في Python يُنفّذ طريقتين:
__iter__()— تُرجع الكائن نفسه (أو مُكرّراً له)__next__()— تُرجع العنصر التالي أو تُطلقStopIteration
Python تستدعي __iter__ عند بداية حلقة for، ثم تستدعي __next__ في كل دورة حتى تصل لـStopIteration.
المولدات — Generators
كتابة __iter__ و__next__ يدوياً ممكنة لكنها طويلة. Python تُتيح طريقة أكثر إيجازاً عبر كلمة yield. دالة تحتوي على yield تصبح تلقائياً مولّداً (Generator).
الفرق الجوهري بين return وyield:
returnتُنهي الدالة نهائياً وتُرجع قيمة واحدةyieldتُعلّق تنفيذ الدالة، تُرجع قيمة، وتنتظر حتى يُطلب العنصر التالي — ثم تستمر من نفس النقطة
التقييم الكسول — Lazy Evaluation
هنا تكمن القوة الحقيقية للمولدات: الذاكرة.
مولّد لا نهائي ممكن لأن القيم تُنتج عند الطلب. قائمة لا نهائية مستحيلة لأنها تحتاج ذاكرة لا نهائية.
تعابير المولدات — Generator Expressions
مثل list comprehensions لكن بأقواس دائرية () بدلاً من معكوفة []:
any() وall() مع المولدات كسولة — تتوقف بمجرد معرفة الإجابة دون المرور على بقية العناصر.
yield from — التفويض للمولدات
yield from تُفوّض التكرار لمولّد أو تسلسل آخر، وهي أوضح وأكفأ من حلقة for مع yield.
متى تستخدم المولدات؟
المولدات مثالية في هذه الحالات:
- تسلسلات كبيرة — ملايين السجلات من قاعدة بيانات، سطور ملف ضخم
- تسلسلات لا نهائية — تسلسل Fibonacci، أعداد طبيعية، أحداث شبكة مستمرة
- خطوط معالجة (Pipelines) — عدة مراحل تحويل على البيانات
- حين تريد نتائج كسولة — حسب الطلب فقط لا دفعة واحدة
لا تستخدم مولدات إذا احتجت الوصول العشوائي للعناصر (بالفهرس) أو احتجت معرفة طول التسلسل مسبقاً — استخدم قوائم بدلاً من ذلك.