2.13. Lusbesturing

Twee sleutelwoorden veranderen hoe een lus verloopt:

  • break – verlaat de lus onmiddellijk.

  • continue – sla de rest van de huidige iteratie over en begin de volgende.

Beide gelden voor de binnenste lus waarin ze voorkomen.

2.13.1. break

Gebruik break om een lus te stoppen zodra aan een voorwaarde is voldaan. Het klassieke patroon “zoeken en stoppen”:

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

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

In een while True:-lus is break de manier waarop de lus eindigt:

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

2.13.2. continue

Gebruik continue om de rest van de body over te slaan en naar de volgende iteratie te springen. Handig om items binnen een lus te filteren:

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

Hetzelfde effect kun je schrijven als een if-blok rond de rest van de body. continue is soms duidelijker wanneer de overslaan-voorwaarde gemakkelijker vooraf te formuleren is dan de behoud-voorwaarde.

Binnen een lus vervult continue dezelfde rol als een vroege return in een functie: sla de gevallen die je niet afhandelt over en houd het hoofdwerk vlak op de buitenste inspringing. De filter-en-verwerk-lus is de canonieke vorm:

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

De ingesprongen regel process(item) is het eigenlijke werk; elke bewaker erboven beschrijft precies welke items worden overgeslagen.

2.13.3. else op een lus

Zowel for als while accepteren een optioneel else-blok. Het wordt uitgevoerd wanneer de lus voltooit zonder een break te raken. Het meest voorkomende gebruik is een zoeklus die een terugval wil als er niets is gevonden:

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

Als een break afgaat, wordt het else-blok overgeslagen. Lees de constructie als “for X in Y: …; of anders, als we er nooit uitbraken, doe Z.”

2.13.4. Veelvoorkomende luspatronen

Een paar patronen duiken vaak op in echte scripts:

  • Pollen – wacht tot een bepaalde voorwaarde waar wordt voordat je verdergaat. De body gebruikt pass, Pythons no-op-instructie; elk ingesprongen blok moet ten minste één instructie bevatten, en pass is de manier om “doe hier niets” te zeggen:

    while not ready():
        pass
    proceed()
    
  • Toestandsmachine – een enkele while True:-lus die kiest wat te doen op basis van een toestandsvariabele. Nuttig wanneer het werk netjes opsplitst in een paar genoemde fasen:

    state = "header"
    for line in lines:
        if state == "header":
            if line.startswith("---"):
                state = "body"
        elif state == "body":
            print(line)
    
  • Accumuleren – bouw een resultaat op terwijl je een reeks doorloopt:

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

    Veel accumulatielussen hebben een one-liner-equivalent met een ingebouwde functie. Gebruik de ingebouwde functie wanneer er een van toepassing is:

    • sum() – telt elk item in een iterable op.

    • max() / min() – het grootste of kleinste item.

    • any()True als minstens één item waarheidsgetrouw is.

    • all()True alleen wanneer elk item waarheidsgetrouw is.

    • sorted() – een nieuwe lijst met de items in volgorde.

    • len() – het aantal items (waar de iterable zijn lengte kent).

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

    De ingebouwde versie is korter, duidelijker en meestal sneller dan dezelfde lus met de hand schrijven.