في الدرس السابق من سلسلة تعلم بايثون، تعرفنا على كيفية اتخاذ القرارات البرمجية وتوجيه مسار التنفيذ باستخدام الجمل الشرطية مثل if و elif و else. هذا يتيح لبرنامجك التعامل مع المدخلات المتنوعة وتنفيذ مسارات مختلفة بناءً على الشروط. ولكن، ماذا لو احتجت إلى تنفيذ نفس الكتلة من الكود مئات أو آلاف المرات؟ هل ستكتب نفس السطر يدوياً مئات المرات؟ بالطبع لا؛ فهذا يناقض أبسط قواعد هندسة البرمجيات التي تهدف إلى الأتمتة والكفاءة.
هنا تأتي أهمية الحلقات التكرارية (Loops). الحلقات التكرارية هي إحدى أبرز الأدوات البرمجية التي تمنحك القدرة على أتمتة المهام المتكررة بكفاءة عالية، مما يوفر الجهد ويقلل أخطاء الكتابة اليدوية. في هذا الدليل الشامل، سنغوص بعمق في النوعين الأساسيين من الحلقات التكرارية في لغة بايثون: حلقة for وحلقة while، وسنتعلم متى نستخدم كل منهما، وكيف نستفيد من أدوات التحكم المتقدمة مثل break و continue، وكيف نتجنب الأخطاء الشائعة التي يقع فيها المبرمجون المبتدئون.
ما هي الحلقات التكرارية ولماذا نحتاجها؟
تخيل أنك تريد طباعة الأرقام من 1 إلى 10. بدون استخدام الحلقات، ستضطر لكتابة أمر الطباعة عشر مرات متتالية، هكذا:
print(1)
print(2)
print(3)
# وهكذا حتى الرقم 10هذا الأسلوب غير عملي بالمره، ويصبح مستحيلاً تماماً إذا أردت معالجة ملف ضخم يحتوي على مليون سجل بيانات. الحلقات التكرارية تختصر هذا الجهد عبر تكرار كتلة من الأوامر البرمجية طالما أن الشرط محقق، أو عبر المرور المتسلسل على عناصر مجموعة بيانات محددة.
في لغة بايثون، تنقسم الحلقات التكرارية بشكل أساسي إلى نوعين رئيسيين، لكل منهما فلسفته واستخدامه الأمثل:
- حلقة التكرار For: تُستخدم عندما تعلم مسبقاً عدد مرات التكرار، أو عندما تريد المرور والتجول بداخل عناصر مجموعة بيانات متسلسلة (مثل القوائم، النصوص، أو القواميس).
- حلقة التكرار While: تُستخدم عندما لا تكون متأکداً مسبقاً من عدد مرات التكرار، وتعتمد استمرارية الحلقة بالكامل على تحقق شرط معين يتغير ديناميكياً أثناء تشغيل البرنامج.
حلقة التكرار For (For Loop) في بايثون
تعتبر حلقة for في بايثون الأسهل والأكثر استخداماً، وتختلف في صياغتها عن لغات برمجة تقليدية أخرى (مثل C أو Java). فبينما تعتمد تلك اللغات على عداد رقمي وشرط تقليدي، تعمل حلقة for في بايثون كعملية "مرور" أو "تiter" (Iterate) عبر عناصر مجموعة بيانات جاهزة.
الشكل العام لبناء حلقة for يعتمد على الكلمة المفتاحية in:
for item in sequence:
# الكود الذي يتم تكراره في كل دورة
print(item)لنأخذ مثالاً عملياً يوضح كيفية التعامل مع القوائم (Lists). لنفترض أن لدينا قائمة تحتوي على أسماء بعض الفواكه، ونريد طباعة رسالة ترحيبية لكل فاكهة في سطر منفصل:
fruits = ["تفاح", "موز", "برتقال", "عنب"]
for fruit in fruits:
print("أنا أحب أكل:", fruit)
print("انتهت القائمة بنجاح!")شرح تفصيلي لتنفيذ الكود:
- أنشأنا أولاً متغيراً باسم
fruitsوهو عبارة عن قائمة (List) تحتوي على أربعة عناصر نصية. - تبدأ حلقة
forبالعبارةfor fruit in fruits:. - يعمل المتغير
fruitكمتغير مؤقت يتم إنشاؤه تلقائياً، ويأخذ قيمة كل عنصر داخل القائمةfruitsواحداً تلو الآخر في كل دورة تكرار (Iteration). - في الدورة الأولى، تكون قيمة
fruitهي "تفاح"، فيطبع البرنامج عبارة "أنا أحب أكل: تفاح". - في الدورة الثانية، تنتقل القيمة تلقائياً لتصبح "موز"، وهكذا حتى تنتهي كافة عناصر القائمة.
- بمجرد استنفاد جميع العناصر، يخرج التنفيذ من نطاق الحلقة وينتقل السطر التالي الذي يقع خارج المسافة البينية، لطباعة "انتهت القائمة بنجاح!".
استخدام دالة range() مع حلقة For
في كثير من الحالات، لن تكون لديك قائمة جاهزة، بل ستحتاج إلى تكرار كتلة من الكود لعدد محدد وثابت من المرات، مثل طباعة الأرقام من 0 إلى 4. توفر لنا لغة بايثون دالة مدمجة وممتازة لهذا الغرض تسمى range() لتوليد تسلسلات عددية بكفاءة عالية دون الحاجة لتخزينها في الذاكرة.
for i in range(5):
print("الرقم الحالي هو:", i)عند تمرير الرقم 5 إلى دالة range()، فإنها تبدأ العد افتراضياً من الصفر 0 وتتوقف قبل الرقم المحدد بدورة واحدة، أي أن القيم الناتجة ستكون: 0، 1، 2، 3، و 4.
كما يمكنك تخصيص دالة range() لتحديد نقطة البداية والنهاية ومقدار الخطوة (Step) هكذا:
# البداية من 2، النهاية قبل 10، بمقدار زيادة 2
for num in range(2, 10, 2):
print(num)
# النتيجة المطبوعة ستكون: 2, 4, 6, 8حلقة التكرار While (While Loop)
بينما تُستخدم حلقة for غالباً لتكرار محدد المعالم أو المرور على مجموعات، فإن حلقة while تعمل بطريقة ديناميكية مختلفة. إنها تشبه الجملة الشرطية if في فحص الشروط، ولكنها تعيد تنفيذ الكتلة البرمجية مراراً وتكراراً طالما أن الشرط المقابل يحمل القيمة المنطقية True.
الشكل العام لبناء حلقة while:
while condition:
# الكود الذي يتكرر طالما الشرط صحيح
# يجب التأكد من تحديث متغير الشرط هنالنفهم ذلك عبر تطبيق عملي لعداد يبدأ من الرقم 1 ويصعد تدريجياً حتى يصل إلى الرقم 3:
counter = 1
while counter <= 3:
print("قيمة العداد الحالية هي:", counter)
counter += 1
print("انتهت حلقة الWhile بنجاح.")تحليل خطوة بخطوة لتنفيذ حلقة While:
- بدأنا بتعريف متغير عداد باسم
counterوأسندنا إليه القيمة الأولية1. - وضعنا شرطاً للحلقة وهو
counter <= 3. - بما أن 1 أقل من أو يساوي 3 (True)، يدخل البرنامج داخل نطاق الحلقة.
- يطبع البرنامج قيمة العداد الحالية، ثم ينفذ السطر الحيوي:
counter += 1والذي يعني زيادة قيمة العداد بمقدار واحد (لتصبح القيمة الجديدة 2). - يعود البرنامج تلقائياً لفحص الشرط من جديد: هل 2 أقل من أو يساوي 3؟ نعم، إذن تتكرر العملية.
- تستمر هذه العملية حتى تصبح قيمة
counterمساوية للرقم 4. عندئذٍ يصبح الشرط4 <= 3خاطئاً (False)، فتتوقف الحلقة فوراً وينتقل مسار التنفيذ لطباعة جملة الخروج النهائية.
التحكم في مسار الحلقات: Break و Continue
أثناء كتابة البرامج المعقدة، قد تحتاج في بعض الأحيان إلى إيقاف حلقة التكرار تماماً قبل وصولها لنهايتها الطبيعية بناءً على شرط طارئ ظهر أثناء التنفيذ، أو قد تحتاج فقط إلى تخطي دورة تكرار واحدة والانتقال مباشرة للدورة التي تليها. توفر لغة بايثون كلمتين رئيسيتين للتحكم الدقيق في سلوك الحلقات:
- الكلمة
break: تُستخدم لكسر وإيقاف الحلقة بالكامل فوراً والخروج خارج نطاقها، بغض النظر عن حالة الشرط الأصلي. - الكلمة
continue: تُستخدم لتخطي باقي الأوامر البرمجية في الدورة الحالية فقط، والقفز مباشرة لبدء الدورة التكرارية التالية.
إليك مثال عملي يوضح استخدام break للبحث عن رقم معين داخل قائمة، وإيقاف عملية البحث بمجرد العثور عليه لتوفير الموارد:
numbers = [10, 20, 30, 40, 50]
for num in numbers:
if num == 30:
print("وجدنا الرقم 30! سنوقف عملية البحث فوراً.")
break
print("تم فحص الرقم:", num)
print("خرجنا من حلقة التكرار.")في هذا المثال، عندما يصل التنفيذ إلى الرقم 30، يتحقق الشرط num == 30، فيقوم البرنامج بطباعة رسالة النجاح ثم يُنفذ الأمر break. هذا الأمر ينهي حلقة for بالكامل ويتجاهل تماماً فحص الرقمين المتبقيين (40 و 50)، مما يرفع من كفاءة البرنامج خاصة عند التعامل مع مجموعات بيانات ضخمة.
أما عن استخدام continue، فيمكننا استعراض مثال بسيط لتخطي طباعة رقم معين:
for i in range(1, 6):
if i == 3:
continue # تخطي الرقم 3 وعدم طباعته
print("الرقم:", i)
# النتيجة: سيتم طباعة الأرقام 1, 2, 4, 5 ويتم تجاهل الرقم 3الأخطاء الشائعة والقيود التي يجب تجنبها
عند التعامل مع الحلقات التكرارية في بدايات رحلتك البرمجية، قد تقع في بعض الأخطاء الشائعة. معرفة هذه الأخطاء وأسبابها سيجنبك الكثير من الإحباط:
- الحلقة اللانهائية (Infinite Loop): هذا هو الخطأ الأكثر شهرة وشيوعاً عند استخدام حلقات
while. يحدث هذا الخطأ عندما تنسى تحديث متغير الشرط داخل جسم الحلقة، بحيث يظل الشرط محققاً (True) للأبد. إذا علق برنامجك وتوقف عن الاستجابة وظل يطبع مخرجات بلا توقف، فهذه حلقة لانهائية. لإيقاف تشغيل البرنامج يدوياً في بيئة التطوير أو سطر الأوامر، يمكنك الضغط على مفتاحيCtrl + C. - نسيان المسافات البينية (Indentation): لغة بايثون تعتمد بشكل أساسي وهيكلي على المسافات البينية (Indentation) لتحديد نطاق الأكواد. أي سطر برمجي تريد تنفيذه داخل الحلقة يجب أن يكون مزاحاً للداخل بمسافة صحيحة وثابتة. نسيان هذه المسافة يسبب خطأ فادحاً في بناء الجملة يُعرف بـ
IndentationError. - الخلط بين استخدام For و While: استخدام حلقة
whileفي مواقف تكون فيها حلقةforهي الخيار الأنسب والأبسط يزيد من تعقيد الكود، ويضاعف من احتمالية الوقوع في أخطاء منطقية أو حلقات لانهائية غير مدعومة بعداد تلقائي.
خلاصة الدرس
الحلقات التكرارية بنوعيها الرئيسييين (for و while) تمثل العصب الأساسي لكتابة برامج ذكية ومرنة قوية تتولى المهام الروتينية والمتكررة نيابة عنك. تذكر دائماً القاعدة الذهبية لاختيار نوع الحلقة المناسبة:
- استخدم حلقة for عندما تتعامل مع مجموعات بيانات محددة العناصر، أو عندما ترغب في تكرار أمر لعدد معروف مسبقاً من المرات.
- استخدم حلقة while عندما يعتمد استمرار وتوقف العمل على تحقق شرط منطقي ديناميكي، مع ضرورة التأكد دائماً من تحديث متغيرات الشروط داخل الحلقة لتجنب خطر الوقوع في الحلقات اللانهائية.
في الدرس القادم من سلسلتنا، سنتناول موضوعاً مركزياً وهو الدوال (Functions)، وكيفية تنظيم وتنظيف كودك البرمجي وتقسيمه إلى أجزاء مستقلة وقابلة لإعادة الاستخدام بسهولة واحترافية.