أساسيات

الحلقات والشروط في Python: for وwhile وrange وenumerate وbreak وif/elif وmatch/case

آخر تحديث: · Skillaria.Top

الحلقات في Python تكرر التنفيذ: تمر for على عناصر أي مجموعة أو على range()، وتستمر while ما دام الشرط صحيحاً. تُنهى الحلقة بـ break، ويُتخطى التكرار الحالي بـ continue، وتُتخذ القرارات بـ if/elif/else أو match/case. وتقلل enumerate وzip الحاجة إلى العدادات اليدوية.

تُستخدم الحلقات في Python لتكرار عمل: المرور على قائمة المشتريات، ومعالجة كل سطر من ملف، أو سؤال المستخدم حتى يُدخل رقماً صحيحاً. في اللغة حلقتان أساسيتان هما for وwhile، والشروط if/elif/else والعامل match/case تساعد على اتخاذ القرار داخلهما. وفيما يلي شرح كل أداة بأمثلة عملية.

الشروط: if وelif وelse

تنفّذ جملة الشرط كتلة من الكود فقط إذا كان التعبير صحيحاً. وتُحدَّد الكتلة بمسافة بادئة من 4 مسافات، فلا توجد أقواس معقوفة في Python، والمسافة البادئة الخاطئة تعطي IndentationError فوراً.

spent = 4200
limit = 5000

if spent > limit:
    print("تم تجاوز الحد")
elif spent > limit * 0.8:
    print("متبقٍ أقل من 20% من الميزانية")
else:
    print("كل شيء على ما يرام")

تُفحص فروع elif من الأعلى إلى الأسفل، ولا ينفذ منها إلا أول فرع مطابق. لذلك ضع الشروط الأكثر صرامة في الأعلى: لو وُضع الشرط spent > limit * 0.8 أولاً لما ظهرت رسالة تجاوز الحد أبداً.

ما الذي يُعدّ صحيحاً

لا يلزم كتابة مقارنة داخل الشرط. القيم الخاطئة هي False وNone والصفر (0 و0.0) والمجموعات الفارغة: "" و[] و{}. وكل ما عدا ذلك صحيح. لذلك يُكتب التحقق من أن القائمة غير فارغة بإيجاز:

expenses = []
if not expenses:
    print("لا توجد مصروفات بعد")

تُدمج الشروط بـ and وor وnot، ويُفحص النطاق بسلسلة مقارنات: if 0 < amount <= 100_000:. ولاختيار قيمة قصيرة يوجد التعبير الشرطي: status = "كثير" if spent > limit else "طبيعي".

حلقة for في Python: الصياغة والأمثلة

حلقة for في Python ليست عدّاداً كما في C، بل هي مرور على العناصر. تأخذ كل عنصر في المجموعة القابلة للتكرار بالترتيب: قائمة أو نص أو قاموس أو ملف أو مجال. ما يُسمى foreach في لغات أخرى هو نفسه for العادية هنا.

expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
    total += amount
print(total)  # 6139

صياغة الحلقة: for متغير in مجموعة:، ثم كتلة بمسافة بادئة. يحتفظ المتغير بعد انتهاء الحلقة بآخر قيمة فيه، وهذا مفيد أحياناً، لكن لا ينبغي الاعتماد عليه في البرامج الكبيرة.

الحلقة على النص والقائمة والقاموس

يُمرّ على النص محرفاً محرفاً، وعلى القائمة عنصراً عنصراً. والحلقة على القاموس تمر على المفاتيح افتراضياً، وللحصول على المفتاح والقيمة معاً استخدم .items():

by_category = {"طعام": 3200, "مواصلات": 900, "سينما": 600}

for category, amount in by_category.items():
    print(f"{category}: {amount} ريال")

وللقيم وحدها يوجد .values(). لا يجوز تغيير حجم القاموس أثناء المرور عليه، فسيظهر RuntimeError: dictionary changed size during iteration. وإذا أردت حذف عناصر فمرّ على نسخة: for key in list(d):.

الدالة range: الحلقة على الأرقام

عند الحاجة إلى المرور على أرقام تأتي range(). لا تنشئ قائمة في الذاكرة، بل تعطي الأرقام واحداً تلو الآخر، لذلك يعمل range(10**9) فوراً.

الاستدعاءالأرقام
range(5)0، 1، 2، 3، 4
range(2, 6)2، 3، 4، 5
range(0, 10, 3)0، 3، 6، 9
range(5, 0, -1)5، 4، 3، 2، 1

القاعدة الأساسية: الحد الأيمن لا يدخل في المجال. فالتعبير range(1, 10) ينتهي عند 9، وهذا سبب شائع للخطأ «بمقدار واحد». يمكن أن تكون الخطوة سالبة، لكن لا يمكن أن تكون صفراً.

for i in range(1, 4):
    print(f"اليوم {i}")
# اليوم 1
# اليوم 2
# اليوم 3

enumerate: عداد داخل الحلقة

يكتب المبتدئون كثيراً for i in range(len(items)) ليعرفوا رقم العنصر. وهذا يعمل، لكنه أقل وضوحاً. تُعيد الدالة enumerate() أزواج «الرقم، العنصر»، والمعامل start يحدد الرقم الذي يبدأ منه العد:

items = ["قهوة", "تاكسي", "غداء"]
for n, item in enumerate(items, start=1):
    print(n, item)
# 1 قهوة
# 2 تاكسي
# 3 غداء

للمرور المتوازي على قائمتين توجد zip(): for name, price in zip(names, prices):. وهي تتوقف عند أقصر قائمة، ومنذ Python 3.10 يمكن تمرير strict=True فيُرفع خطأ إذا اختلف الطول.

حلقة while في Python

تكرر حلقة while الكتلة ما دام الشرط صحيحاً. وتُختار عندما لا يُعرف عدد التكرارات مسبقاً: انتظار إدخال صحيح، أو قراءة البيانات حتى نهايتها، أو تكرار الطلب حتى ينجح.

balance = 10_000
month = 0
while balance > 0:
    balance -= 2_700
    month += 1
print(f"يكفي المال لمدة {month} أشهر")  # 4

الخطر الأكبر هو نسيان تغيير المتغير الموجود في الشرط، فتستمر الحلقة إلى ما لا نهاية. وإذا «تجمّد» البرنامج فاضغط Ctrl+C، فيقطع Python التنفيذ برسالة KeyboardInterrupt.

الحلقة اللانهائية وما يشبه do while

أحياناً تُكتب الحلقة اللانهائية عمداً: while True: مع الخروج بـ break. وبهذه الطريقة تُكتب أيضاً الحلقة ذات الشرط اللاحق، فليس في Python بنية do while، ويعوّضها هذا الأسلوب: ينفَّذ الجسم مرة واحدة على الأقل، ويقع الفحص في الآخر.

while True:
    raw = input("المبلغ: ")
    if raw.isdigit():
        amount = int(raw)
        break
    print("أدخل عدداً صحيحاً")

الحلقة for لا تكون لانهائية إلا نادراً، وذلك عند المرور على مكرّر لا ينتهي، مثل itertools.count().

break وcontinue: الخروج من الحلقة وتخطي التكرار

تُنهي break الحلقة فوراً، وينتقل التنفيذ إلى الكود الذي بعدها. أما continue فتتخطى باقي التكرار الحالي وتنتقل إلى التالي.

expenses = [350, -10, 1200, 0, 99_999, 89]

for amount in expenses:
    if amount <= 0:
        continue          # تخطي هذا التكرار
    if amount > 50_000:
        print("مبلغ مشبوه، إيقاف")
        break             # الخروج من الحلقة
    print(amount)

سيُطبع 350 ثم 1200، بعدها تظهر رسالة الإيقاف، فلا تصل الحلقة إلى 89. وكلا الأمرين يؤثران في أقرب حلقة يوجدان فيها فقط.

else في الحلقة

لكل من for وwhile فرع else غير معتاد: ينفَّذ إذا انتهت الحلقة بنفسها، أي دون break. وهذا مفيد في البحث:

for amount in expenses:
    if amount > 50_000:
        print("وجدنا مصروفاً كبيراً")
        break
else:
    print("لا توجد مصروفات كبيرة")

الحلقات المتداخلة

الحلقة داخل حلقة تنفّذ الداخلية كاملة مع كل تكرار للخارجية. وبهذا تُمرّ على الجداول والمصفوفات والأزواج.

for row in range(1, 4):
    for col in range(1, 4):
        print(row * col, end="\t")
    print()

انتبه إلى أمرين. أولاً، التعقيد يرتفع بسرعة: حلقتان متداخلتان على 10000 عنصر تعنيان 100 مليون عملية. ثانياً، break يخرج من الحلقة الداخلية فقط. ولإيقاف الحلقتين معاً انقل الحلقات إلى دالة واستخدم return، فهذا أنظف من استخدام الأعلام.

العامل match/case

سلسلة if cmd == ... elif ... الطويلة يمكن استبدالها منذ Python 3.10 بالعامل match (PEP 634). وليس هذا مجرد switch: إنه يطابق القيمة مع نمط حسب شكل البيانات، ويوزّع أجزاءها مباشرة على متغيرات.

def parse(text):
    match text.split():
        case ["add", item, amount]:
            return f"إضافة {item}: {amount}"
        case ["list"] | ["ls"]:
            return "عرض المصروفات"
        case ["quit"]:
            return "خروج"
        case _:
            return "أمر غير معروف"

print(parse("add قهوة 250"))  # إضافة قهوة: 250
print(parse("add قهوة"))      # أمر غير معروف

النمط القائمي ["add", item, amount] يطابق فقط القائمة التي فيها ثلاثة عناصر بالضبط، أولها "add". لذلك يذهب الأمر بدون مبلغ إلى الفرع _ الذي يلتقط كل ما عداه. والرمز | يجمع بين البدائل.

القواميس والأنواع وشرط الحراسة

نمط القاموس يفحص المفاتيح المذكورة فقط، وتُتجاهل المفاتيح الزائدة. والتعبير int(a) يفحص النوع ويلتقط القيمة، والشرط if بعد النمط يضيف شرطاً إضافياً يُسمى الحارس (guard):

match event:
    case {"type": "expense", "amount": int(a)} if a > 10_000:
        print("مصروف كبير", a)
    case {"type": "expense", "amount": int(a)}:
        print("مصروف", a)

الفخ الرئيسي في match

الاسم المجرد في case يعني التقاط القيمة، لا المقارنة مع متغير. فالتعبير case limit: يطابق أي قيمة ويكتبها في limit. للمقارنة مع ثوابت استخدم اسماً بنقطة، مثل case Color.RED:، أو قيماً حرفية.

لم يتغير نحو match تقريباً منذ 3.10. وفي Python 3.15 أُغلقت فجوة صغيرة: كانت الأنماط الحرفية تسمح بالناقص قبل الرقم فقط، والآن يمكن كتابة case +1: أيضاً. وعلى الإصدارات الأقدم سيعطي هذا الكود خطأ نحوياً.

أخطاء شائعة في الحلقات

  • تعديل القائمة أثناء المرور عليها. حذف العناصر داخل for يتخطى العناصر المجاورة. الأفضل بناء قائمة جديدة: clean = [x for x in items if x > 0].
  • حد range. range(1, n) لا يشمل n.
  • نسيان تغيير الشرط في while، فتصبح الحلقة لانهائية.
  • دمج النصوص بـ += داخل الحلقة بكميات كبيرة أبطأ من "".join(parts).
  • الإسناد بدل المقارنة: if x = 5 خطأ نحوي، والمقارنة تُكتب ==.

تمارين على الحلقات

  1. احسب مجموع ومتوسط قائمة مصروفات، متجاوزاً القيم السالبة.
  2. اطبع جدول الضرب من 1 إلى 9 بحلقات متداخلة.
  3. اسأل المستخدم عن أرقام حتى يُدخل سطراً فارغاً، ثم اطبع الأكبر.
  4. ابحث عن أول رقم أكبر من 1000 في قائمة، وأبلغ إذا لم يوجد (باستخدام for ... else).
  5. حلّل الأوامر add وdel وlist بالعامل match.

الخلاصة

الحلقات في Python تقوم على بنيتين: تمرّ for على عناصر المجموعة أو range()، وتعمل while ما دام الشرط صحيحاً. وتتحكم break وcontinue في سير الحلقة، وتلغي enumerate() وzip() العدادات اليدوية، وتتخذ if/elif/else وmatch/case القرارات. وقد شُرحت هذه الأدوات عملياً في الدورة، من خلال متتبّع المصروفات.

الأسئلة الشائعة

ما الفرق بين for وwhile في Python؟

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

كيف أمر على حلقة بالترتيب العكسي؟

استخدم reversed(items) مع المجموعات، أو range(n - 1, -1, -1) مع الأرقام. ولا تنسخ reversed القائمة، بل تمر عليها من النهاية.

هل يوجد switch في Python؟

لا يوجد switch منفصل، ويقوم بدوره سلسلة if/elif أو العامل match/case الذي ظهر في Python 3.10. وmatch أقوى منه، فهو يفكك القوائم والقواميس حسب شكلها ويلتقط القيم.

أيهما أسرع: الحلقة أم مولّد القائمة؟

مولّد القائمة مثل [x * 2 for x in items] يكون عادةً أسرع قليلاً من الحلقة المكافئة التي تستخدم append، وأقصر. أما المنطق المعقد بعدة شروط فتكون الحلقة العادية أوضح.

كيف أخرج من حلقتين متداخلتين معاً؟

break يخرج من الحلقة الداخلية فقط. أسهل حل هو نقل الحلقات إلى دالة والخروج منها بـ return.

تعلّم هذا الموضوع بالفيديو

يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Python 3.15: от новичка до профи».

الانتقال إلى الدورة