Iterators في بايثون: 🔄 المفتاح السحري للتنقل في البيانات
مرحباً بك في درس جديد ومهم جداً! إذا كنت قد تساءلت من قبل عن كيف تعمل الحلقة for في بايثون خلف الكواليس لتتمكن من المرور على كل عنصر في قائمة أو مجموعة بيانات، فإن الإجابة تكمن في مفهوم المكررات (Iterators). في هذا الدرس، سنفتح هذا الصندوق الأسود معاً خطوة بخطوة.
ما هو الـ Iterator؟ 🤔
ببساطة شديدة، الـ Iterator هو كائن يمكننا أن نطلب منه عنصراً واحداً في كل مرة من سلسلة من العناصر. تخيل أن لديك صندوقاً من قطع الشوكولاتة. الـ Iterator هو مثل الشخص المسؤول الذي يمد يده إلى الصندوق ويعطيك قطعة واحدة فقط عندما تطلبها أنت. لا يعطيك كل القطع مرة واحدة، بل يعطيك إياها واحدة تلو الأخرى.
في عالم بايثون، الـ Iterator هو أي كائن يتبع "بروتوكول المكرر". هذا البروتوكول يتطلب أن يكون للكائن وظيفتين رئيسيتين:
__iter__(): والتي تُرجع الكائن المكرر نفسه.__next__(): والتي تُرجع العنصر التالي في التسلسل.
عندما لا يتبقى المزيد من العناصر، يجب على دالة __next__() أن ترفع استثناءً (خطأ) خاصاً يسمى StopIteration لتنبيهنا بأننا انتهينا.
الفرق الأساسي: Iterable مقابل Iterator
من المهم جداً أن نفرق بين مفهومين:
- Iterable (كائن قابل للتكرار): هو أي كائن يمكنك الحصول منه على مكرر (Iterator). الأمثلة الأكثر شيوعاً هي: القوائم (
list)، tuples (tuple)، السلاسل النصية (str)، والقواميس (dict). هذا الكائن يحتوي على البيانات. - Iterator (المكرر): هو الكائن المسؤول فعلياً عن تنفيذ عملية التكرار وذكر موقعنا الحالي في التسلسل.
لتحويل كائن Iterable إلى Iterator، نستخدم الدالة المدمجة iter().
# مثال: تحويل قائمة (Iterable) إلى Iterator
my_list = ["Apple", "Banana", "Orange"] # هذا Iterable
my_iterator = iter(my_list) # نحصل على Iterator باستخدام iter()
print(my_iterator) # سيطبع شيئاً مثل: <list_iterator object at 0x...>
شرح الكود: هنا، my_list هو الكائن القابل للتكرار الذي يحتوي على البيانات. عندما نستخدم iter(my_list)، نحصل على كائن مكرر (my_iterator) جاهز لبدء إعطائنا العناصر واحدة تلو الأخرى.
كيف نستخدم Iterator يدوياً؟ 👐
الطريقة المباشرة لاستخدام Iterator هي باستدعاء الدالة المدمجة next() عليه. كل مرة تستدعي next()، تحصل على العنصر التالي في التسلسل.
# متابعة المثال السابق
my_list = ["Apple", "Banana", "Orange"]
my_iterator = iter(my_list)
# نطلب العناصر واحدة تلو الأخرى باستخدام next()
first_item = next(my_iterator)
print(first_item) # الناتج: Apple
second_item = next(my_iterator)
print(second_item) # الناتج: Banana
third_item = next(my_iterator)
print(third_item) # الناتج: Orange
# ماذا سيحدث الآن؟ لقد انتهت العناصر!
# fourth_item = next(my_iterator) # سيتسبب هذا في خطأ StopIteration
شرح الكود: نرى كيف أن next() تتذكر مكانها. في كل استدعاء، تتحرك إلى العنصر التالي. عندما تصل إلى النهاية وتستدعى مرة أخرى، ترفع استثناء StopIteration لإعلامنا بأن العملية اكتملت.
السر الحقيقي behind حلقات For 🕵️♂️
الآن أصبح بإمكانك فهم السحر الكامن وراء الحلقة for! عندما تكتب حلقة for، تقوم بايثون تلقائياً بما يلي:
- تستدعي
iter()على الكائن القابل للتكرار (مثل القائمة) للحصول على كائن مكرر. - تستدعي
next()بشكل متكرر على هذا المكرر. - تعين القيمة التي تُرجعها
next()إلى متغير الحلقة (مثلitem). - تتوقف تلقائياً عندما تلتقط استثناء
StopIteration.
لذا، هذان الكودان متطابقان تماماً في الوظيفة:
الطريقة العادية (التي تعرفها):
fruits = ["Apple", "Banana", "Orange"]
for fruit in fruits:
print(fruit)
الطريقة اليدوية (كيف تعمل داخلياً):
fruits = ["Apple", "Banana", "Orange"]
iterator = iter(fruits) # 1. الحصول على المكرر
while True:
try:
fruit = next(iterator) # 2. الحصول على العنصر التالي
print(fruit) # 3. تنفيذ جسم الحلقة
except StopIteration: # 4. اكتشاف النهاية
break # 5. الخروج من الحلقة
خلاصة الدرس 🎯
- الـ Iterator هو كائن يسمح لنا بالمرور على عناصر مجموعة بيانات واحدة تلو الأخرى.
- نستخدم الدالة
iter()لإنشاء Iterator من أي كائن Iterable (مثل القائمة). - نستخدم الدالة
next()لطلب العنصر التالي من الـ Iterator. - الحلقة
forفي بايثون هي مجرد "سكر سنتكس" – أي طريقة كتابة مختصرة – تخفي عنا الخطوات اليدوية لاستخدامiter()وnext().
🎓 اختبر نفسك
التعليقات
شاركنا رأيك أو أسئلتك حول هذا المقال