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.