Python: المكرّرات والمولّدات

آخر تحديث: 2026-09-22

لقد كنت تستخدم for x in list: لتكرار البيانات، لكن هل فكرت يوماً في ما يمكن أن يتبع in؟ لماذا لا يستهلك range(1000000) ذاكرة؟ المكرّرات و المولّدات هي الإجابة. تتيح لك التعامل مع تدفقات بيانات "لا نهائية" — تُنتَج عند الطلب، لا تُخزّن في الذاكرة.


دوال مدمجة ذات صلة:reversed() iter() next() return yield for

1. ما هو بروتوكول المكرّر

في بايثون، أي كائن يمكن استخدامه في حلقة for هو قابل للتكرار. إنها تنفذ بروتوكول المكرّر:

▶ مثال: أساسيات بروتوكول المكرّر

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Executed successfully

حلقة for تفعل هذا أساساً:

▶ مثال: محاكاة حلقة for يدوياً

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Executed successfully


2. مكرّرات مخصصة

نفّذ __iter__ و __next__ لجعل فصلك يعمل مع حلقات for:

▶ مثال: مكرّر العد التنازلي

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully

▶ مثال: مكرّر فيبوناتشي (الصعوبة ⭐⭐)

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully


3. المولّدات: yield

كتابة فئة بـ __iter__ و __next__ مملة. دوال المولّدات تستخدم yield لتحقيق نفس الشيء:

▶ مثال: مولّد العد التنازلي

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully

yield يختلف عن return — return ينهي الدالة، بينما yield يُوقفها مؤقتاً، ويتذكر الحالة الحالية، ويستأنف من حيث توقف في الاستدعاء التالي.

▶ مثال: مولّد فيبوناتشي

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Function defined successfully
💡 المولّدات مقابل فئات المكرّرات: دوال المولّدات (yield) عادة ما تكون أكثر إيجازاً بكثير من كتابة فئات المكرّر يدوياً. في معظم السيناريوهات، المولّدات هي الخيار الأول. فكر فقط في كتابة فئة مكرّر إذا كنت بحاجة للحفاظ على حالة معقدة أو تحتاج دوالاً إضافية.



4. التحميل الكسول مع المولّدات

أكبر ميزة للمولّدات — لا تُنشئ جميع البيانات مرة واحدة، بل عند الطلب:

▶ مثال: التحميل الكسول للمولّد

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
Generating 1
Generating 2
Generating 3
Generator created, but not yet executed

هل ترى تدفق التنفيذ؟ كل استدعاء لـ next() ينفذ حتى yield التالي، ثم يتوقف. هذا مفيد بشكل لا يصدق للبيانات الكبيرة:

▶ مثال: قراءة ملف كبير سطراً بسطر

TEXTN
# طريقة "كسولة" لمعالجة الملفات الكبيرة
def read_large_file(filename):
    """اقرأ ملفاً كبيراً سطراً بسطر، دون تحميله كله في الذاكرة"""
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            yield line.strip()

# معالجة بالمولّد — سطر واحد فقط في الذاكرة في كل مرة
for line in read_large_file("huge_log.txt"):
    if "ERROR" in line:
        print(line)  # السرعة محدودة فقط بسرعة قراءة القرص
▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
// Executed successfully


5. تعبيرات المولّدات

مشابهة لشاملات القوائم، لكن بـ أقواس — تعبيرات المولّدات تُقيّم بتكاسل:

▶ مثال: تعبير مولّد

▶ جرّب الكود

الناتج:

TEXT 📖 للعرض فقط
# Executed successfully
المقارنة شاملة قائمة [] تعبير مولّد ()
الذاكرة كل البيانات في الذاكرة عند الطلب، لا شيء تقريباً
السرعة توليد ووصول سريعان كسول، يحسب في كل مرة
قابلية إعادة الاستخدام يمكن التكرار عدة مرات يمكن التكرار مرة واحدة فقط
حالة الاستخدام بيانات صغيرة، استخدام متكرر بيانات كبيرة، مرور واحد
💡 متى تستخدم المولّدات؟ ① مجموعات بيانات كبيرة (آلاف+ العناصر). ② تحتاج فقط للتكرار مرة واحدة. ③ تحتاج معالجة متدفقة (ملف سطراً بسطر، تدفقات بيانات في الوقت الفعلي). ④ تريد التعبير عن "تسلسلات لا نهائية."



6. حالات الاستخدام الشائعة



دوال مدمجة ذات صلة:reversed() iter() next() return yield for

❓ أسئلة شائعة

س ما الفرق بين المولّد والدالة العادية؟
ج الدالة العادية تستخدم return لإرجاع نتيجة مرة واحدة وتنتهي. المولّد يستخدم yield لإنتاج القيم واحدة تلو الأخرى، ويتوقف ويحفظ الحالة بعد كل yield. كل استدعاء لدالة مولّد يُرجع كائن مولّد جديد.
س يمكن تكرار المولّدات مرة واحدة فقط. ماذا لو كنت بحاجة للتكرار عدة مرات؟
ج استخدم list(gen) لتحويل المولّد إلى قائمة. لكن إذا كانت البيانات كبيرة جداً، التحويل إلى قائمة سيستهلك الذاكرة. حل وسط: استخدم itertools.tee() لنسخ المولّد، أو استدع دالة المولّد مرة أخرى لإنشاء واحد جديد.
س هل يمكن أن يتعايش yield و return؟
ج نعم — return في المولّد يوقف التكرار فعلياً ويرفع StopIteration بقيمة اختيارية. لكن نادراً ما يُستخدم. إذا وجدت دالة تحتاج كلاً من yield و return، أعد النظر في التصميم.

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ⭐): اكتب مولّداً even_numbers(max_n) يُنشئ جميع الأرقام الزوجية من 0 إلى max_n.

  2. متوسط (الصعوبة ⭐⭐): اكتب مولّداً repeat_list(items, times) يُكرّر كل عنصر من قائمة times مرة. مثال: list(repeat_list([1, 2, 3], 2)) يُرجع [1, 1, 2, 2, 3, 3].

  3. تحدي (الصعوبة ⭐⭐⭐): اكتب مولّداً deep_flatten(nested) يُسطح القوائم المتداخلة بشكل تعسفي. مثال: list(deep_flatten([1, [2, [3, 4]], 5])) يُرجع [1, 2, 3, 4, 5]. تلميح: كرّر على العناصر؛ إذا كان العنصر قائمة، استخدم yield from للعودية منه.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%