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 เพื่อข้ามส่วนที่เหลือของ body และกระโดดไปยังรอบถัดไป เหมาะสำหรับการกรองรายการภายในลูป:

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

ผลลัพธ์เดียวกันสามารถเขียนเป็นบล็อก if ที่ครอบ body ส่วนที่เหลือ continue บางครั้งชัดเจนกว่าเมื่อเงื่อนไขสำหรับข้ามระบุได้ง่ายกว่าเงื่อนไขสำหรับเก็บไว้

ภายในลูป continue มีบทบาทเดียวกับ return ก่อนกำหนดในฟังก์ชัน: ข้ามกรณีที่ไม่ต้องการจัดการและรักษางานหลักให้อยู่ในระดับ indent ด้านนอก รูปแบบลูปกรอง-และ-ประมวลผลคือรูปแบบมาตรฐาน:

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

บรรทัด process(item) ที่เยื้องเข้าไปคืองานจริง แต่ละ guard ด้านบนระบุอย่างชัดเจนว่ารายการใดถูกข้าม

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 จะถูกข้าม อ่านโครงสร้างนี้ว่า "for X in Y: ...; or-else หากเราไม่เคย break ออกมา ให้ทำ Z"

2.13.4. รูปแบบลูปที่พบบ่อย

รูปแบบบางอย่างปรากฏบ่อยในสคริปต์จริง:

  • Polling -- รอให้เงื่อนไขบางอย่างเป็นจริงก่อนดำเนินการต่อ body ใช้ pass ซึ่งเป็นคำสั่ง no-op ของ Python; ทุกบล็อกที่เยื้องเข้าต้องมีคำสั่งอย่างน้อยหนึ่งคำสั่ง และ pass คือวิธีบอกว่า "ไม่ต้องทำอะไรที่นี่":

    while not ready():
        pass
    proceed()
    
  • State machine -- ลูป while True: เดียวที่เลือกสิ่งที่จะทำตามตัวแปร state มีประโยชน์เมื่องานแบ่งออกเป็นขั้นตอนที่มีชื่อชัดเจน:

    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)
    

    ลูปสะสมหลายรูปแบบมีเทียบเท่าแบบบรรทัดเดียวโดยใช้ built-in เลือกใช้ built-in เมื่อมีให้ใช้:

    • sum() -- รวมทุกรายการใน iterable

    • max() / min() -- รายการที่ใหญ่ที่สุดหรือเล็กที่สุด

    • any() -- True หากมีอย่างน้อยหนึ่งรายการที่เป็น truthy

    • all() -- True เฉพาะเมื่อทุกรายการเป็น truthy

    • sorted() -- list ใหม่ที่มีรายการเรียงตามลำดับ

    • len() -- จำนวนรายการ (เมื่อ iterable รู้ความยาวของตัวเอง)

    >>> 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
    

    เวอร์ชัน built-in สั้นกว่า ชัดเจนกว่า และมักเร็วกว่าการเขียนลูปเองด้วยมือ