2.13. التحكم في الحلقات

هناك كلمتان مفتاحيتان تغيّران طريقة عمل الحلقة:

  • break -- الخروج من الحلقة فورًا.

  • continue -- تخطّي بقية التكرار الحالي والبدء بالتكرار التالي.

كلتاهما تنطبق على الحلقة الأكثر داخليةً التي تظهران ضمنها.

2.13.1. break

استخدم break لإيقاف الحلقة فور تحقّق شرط معيّن. النمط الكلاسيكي "ابحث ثم توقّف":

found = None
for item in items:
    if matches(item):
        found = item
        break

if found is not None:
    print("found:", found)

في حلقة while True:، يكون break هو الطريقة التي تنتهي بها الحلقة:

while True:
    line = next_line()
    if line == "quit":
        break
    process(line)

2.13.2. continue

استخدم continue لتخطّي بقية جسم الحلقة والقفز إلى التكرار التالي. وهو مفيد لتصفية العناصر داخل الحلقة:

for n in numbers:
    if n < 0:
        continue            # skip negatives
    print(n)

يمكن تحقيق التأثير نفسه بكتابة كتلة if تحيط ببقية جسم الحلقة. لكن continue يكون أحيانًا أوضح عندما يكون التعبير عن شرط التخطّي أسهل مقدمًا من التعبير عن شرط الإبقاء.

داخل الحلقة، يؤدّي continue الدور نفسه الذي يؤدّيه return المبكّر داخل الدالة: تخطّي الحالات التي لا تعالجها وإبقاء العمل الرئيسي مستويًا عند الإزاحة الخارجية. وتُعدّ حلقة التصفية والمعالجة هي الشكل النموذجي:

for item in items:
    if item is None:
        continue
    if not item.is_valid():
        continue
    process(item)

السطر المُزاح process(item) هو العمل الفعلي؛ وكل حارس في الأعلى يوضّح بدقة أيّ العناصر يُتخطّى.

2.13.3. else على الحلقة

تقبل كلٌّ من for و while كتلة else اختيارية. وهي تعمل عند اكتمال الحلقة دون أن تصادف break. والاستخدام الأكثر شيوعًا هو حلقة بحث ترغب في بديل احتياطي إذا لم يُعثر على شيء:

for item in items:
    if matches(item):
        print("found:", item)
        break
else:
    print("no match")

إذا أُطلق break، فإن كتلة else تُتخطّى. اقرأ هذا التركيب على أنه "من أجل X في Y: ...؛ وإلّا، إذا لم نخرج إطلاقًا، نفّذ Z."

2.13.4. أنماط الحلقات الشائعة

تظهر بعض الأنماط كثيرًا في البرامج النصية الحقيقية:

  • الاستقصاء (Polling) -- الانتظار حتى يصبح شرط ما صحيحًا قبل المتابعة. يستخدم جسم الحلقة pass، وهو تعليمة عدم العمل في Python؛ إذ يجب أن تحتوي كل كتلة مُزاحة على تعليمة واحدة على الأقل، و pass هي طريقة قول "لا تفعل شيئًا هنا":

    while not ready():
        pass
    proceed()
    
  • آلة الحالة (State machine) -- حلقة while True: واحدة تختار ما يجب فعله بناءً على متغيّر حالة. وهي مفيدة عندما ينقسم العمل بوضوح إلى عدة مراحل مُسمّاة:

    state = "header"
    for line in lines:
        if state == "header":
            if line.startswith("---"):
                state = "body"
        elif state == "body":
            print(line)
    
  • التراكم (Accumulating) -- بناء نتيجة أثناء السير عبر تسلسل:

    total = 0
    for x in samples:
        total += x
    mean = total / len(samples)
    

    لكثير من حلقات التراكم مكافئٌ من سطر واحد باستخدام دالة مدمجة. استخدم الدالة المدمجة متى انطبقت:

    • sum() -- يجمع كل عنصر في كائن قابل للتكرار.

    • max() / min() -- أكبر عنصر أو أصغره.

    • any() -- True إذا كان عنصر واحد على الأقل صحيحًا.

    • all() -- True فقط عندما يكون كل عنصر صحيحًا.

    • sorted() -- قائمة جديدة بالعناصر مرتّبةً.

    • len() -- عدد العناصر (حيث يعرف الكائن القابل للتكرار طوله).

    >>> samples = [3, 1, 4, 1, 5, 9, 2, 6]
    >>> sum(samples)
    31
    >>> sum(samples) / len(samples)        # mean
    3.875
    >>> max(samples)
    9
    >>> min(samples)
    1
    >>> sorted(samples)
    [1, 1, 2, 3, 4, 5, 6, 9]
    >>> any([False, False, True])
    True
    >>> all([True, True, False])
    False
    

    النسخة المدمجة أقصر وأوضح وعادةً أسرع من كتابة الحلقة نفسها يدويًا.