المولدات (Generators) في لغة بايثون هي آلية قوية للتعامل بكفاءة مع تسلسلات البيانات. فهي تتيح لك إنشاء كائنات قابلة للتكرار (iterable) تحسب القيم عند الطلب، مما يوفر ذاكرة النظام بشكل كبير. أساس عمل المولدات هو الكلمة المفتاحية yield، والتي تختلف جوهريًا عن return التقليدية.
أساسيات عمل المولدات في بايثون
المولدات هي دوال خاصة تُرجع مكررات (iterators) بدلاً من قيم محددة. الفرق الرئيسي هو استخدام الكلمة المفتاحية yield، التي تحافظ على حالة الدالة بين الاستدعاءات.
في كل مرة يتم فيها استدعاء الدالة المولدة، يستأنف التنفيذ من النقطة التي توقف عندها آخر أمر yield. وهذا يجعل المولدات حلاً مثاليًا لمعالجة تدفقات البيانات الكبيرة دون الحاجة إلى تحميلها بالكامل في الذاكرة.
def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
for value in gen:
print(value)
النتيجة:
1
2
3
آلية عمل الكلمة المفتاحية yield
تعمل الكلمة المفتاحية yield وفق مبدأ "الحسابات الكسولة" (Lazy Evaluation):
- عند أول استدعاء لـ
next()، يبدأ التنفيذ من بداية الدالة حتى أولyield - بعد إرجاع القيمة، "تُجمّد" الدالة حالتها
- الاستدعاء التالي لـ
next()يستأنف التنفيذ من نقطة التوقف - تستمر العملية حتى انتهاء الدالة
def counter():
print("بداية المولد")
yield 1
print("بعد أول yield")
yield 2
print("بعد ثاني yield")
gen = counter()
next(gen) # ستطبع: بداية المولد
next(gen) # ستطبع: بعد أول yield
مزايا المولدات مقارنة بالقوائم
استخدام المولدات بدلاً من القوائم يعطي مزايا كبيرة عند التعامل مع كميات ضخمة من البيانات:
توفير الذاكرة: المولدات لا تخزن جميع القيم في وقت واحد، بل تُنشئها حسب الحاجة.
# قائمة - تستهلك ذاكرة كبيرة
squares_list = [x * x for x in range(1000000)]
# مولد - استهلاك ضئيل للذاكرة
squares_gen = (x * x for x in range(1000000))
الأداء: المولدات تبدأ في إرجاع القيم فورًا، دون انتظار إنشاء التسلسل الكامل.
إنشاء تسلسلات لا نهائية
تتيح المولدات إنشاء تسلسلات لا نهائية دون خطر تجاوز الذاكرة:
def infinite_counter(start=0):
while True:
yield start
start += 1
counter = infinite_counter()
print(next(counter)) # 0
print(next(counter)) # 1
print(next(counter)) # 2
طرق التعامل مع المولدات
تدعم المولدات عدة طرق متخصصة:
next() — للحصول على القيمة التالية من المولد
send(value) — لإرسال قيمة إلى داخل المولد
throw() — لإثارة استثناء داخل المولد
close() — للإيقاف القسري للمولد
def interactive_generator():
value = yield "البداية"
while True:
value = yield f"تم الاستلام: {value}"
gen = interactive_generator()
print(next(gen)) # البداية
print(gen.send(42)) # تم الاستلام: 42
print(gen.send("مرحبا")) # تم الاستلام: مرحبا
معالجة الاستثناءات في المولدات
تدعم المولدات آلية معالجة الاستثناءات، بما في ذلك الاستثناء الخاص GeneratorExit:
def example_generator():
try:
yield 1
yield 2
except GeneratorExit:
print("تم إغلاق المولد!")
gen = example_generator()
print(next(gen)) # 1
gen.close() # ستطبع: تم إغلاق المولد!