for-lussen en range — een bekend aantal keer uitvoeren
Als je weet hoe vaak iets moet gebeuren, is een for-lus de juiste keuze. De drie vormen van range, waarom het einde wordt uitgesloten, en hoe je kiest tussen for en while.
Hoe wil je leren?
Het probleem dat we oplossen
In het vorige hoofdstuk telde je 1 tot en met 5 op met vier regels, waarvan er twee alleen bestonden om bij te houden hoeveel keer de lus draaide — een startwaarde en een ophoging. Vergeet je de ophoging, dan krijg je een oneindige lus.
Maar let op iets bij dit soort werk: we wisten vooraf hoe vaak het zou draaien. Vijf keer. Als dat zo is, is er geen reden om het bijhouden zelf te doen — dat kun je aan Python overlaten.
Dat is precies wat een for-lus doet. En omdat het tellen niet meer in jouw handen ligt, kan een for-lus over een range niet vanzelf oneindig worden — het aantal rondes ligt vast zodra de lus begint. Dat is zijn grootste voordeel. (Er is één uitzondering: als je over een lijst loopt en binnenin de lus steeds nieuwe items aan diezelfde lijst toevoegt, eindigt de lus nooit. Lijsten komen in het volgende hoofdstuk.)
Aan het einde van dit hoofdstuk kun je
- Code een vast aantal keer laten uitvoeren met een
for-lus - Alle drie vormen van
range()gebruiken - Uitleggen waarom
range(1, 5)vier getallen oplevert, en geen vijf - Over de tekens van een string lopen
- Bepalen welke van
forenwhilebij een bepaalde klus past
Voorkennis: while-lussen — lopen zolang een voorwaarde waar is.
De eenvoudigste vorm
for number in range(5):
print(number)0
1
2
3
4Drie regels werk in één, zonder teller om bij te houden. Lees het zo: "voor elk getal dat `range(5)` oplevert, voer het blok één keer uit — en zet elke keer dat getal in `number`."
Twee dingen vallen meteen op:
Het begint bij nul, en 5 komt nooit voor — vijf getallen in totaal, maar 0 tot en met 4. Dit is dezelfde regel die Python overal toepast: net zoals de eindindex in een slice wordt uitgesloten, gebeurt dat ook in een range.
De naam number kies je zelf. for i in range(5) is net zo goed, en i is de gebruikelijke naam voor een teller. Maar als het getal iets betekent, noem het dan naar die betekenis — for student_number in range(30) is op zichzelf al duidelijk.
De drie vormen van range()
print("--- range(5) ---")
for i in range(5):
print(i, end=" ")
print()
print("--- range(2, 6) ---")
for i in range(2, 6):
print(i, end=" ")
print()
print("--- range(0, 10, 3) ---")
for i in range(0, 10, 3):
print(i, end=" ")
print()
print("--- range(5, 0, -1) ---")
for i in range(5, 0, -1):
print(i, end=" ")
print()--- 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 1De regels:
range(stop)— begint bij0, eindigt vóórstoprange(start, stop)— begint bijstart, eindigt vóórstoprange(start, stop, step)— gaat elke keer metstepomhoog; een negatievesteptelt terug
Controleer de laatste twee. range(0, 10, 3) geeft 0 3 6 9 — de volgende zou 12 zijn, dat is groter dan 10, dus het stopt. En range(5, 0, -1) geeft 5 4 3 2 1 — 0 komt nooit voor, omdat ook hier het einde wordt uitgesloten.
Waarom wordt het einde uitgesloten? Omdat het rekenen dan makkelijk blijft. Hoeveel getallen zitten er inrange(0, 5)?5 - 0, dus vijf. Inrange(3, 8)?8 - 3, ook vijf. Aftrekken geeft je het aantal, zonder dat je hoeft na te denken of je er één bij moet optellen. En twee ranges die direct op elkaar aansluiten —range(0, 5)enrange(5, 10)— missen niets en herhalen niets.
Wanneer je één tot tien wilt
Deze fout komt zo vaak voor dat hij een eigen stukje verdient:
print("Wrong — stops at 9:")
for i in range(1, 10):
print(i, end=" ")
print()
print("Right — includes 10:")
for i in range(1, 11):
print(i, end=" ")
print()Wrong — stops at 9:
1 2 3 4 5 6 7 8 9
Right — includes 10:
1 2 3 4 5 6 7 8 9 10De regel in één zin: schrijf als stop één meer dan het laatste getal dat je wilt.
Optellen — nu op de makkelijke manier
total = 0
for number in range(1, 6):
total = total + number
print("Sum of 1 to 5:", total)Sum of 1 to 5: 15Vergelijk dit met de while-versie van dezelfde klus: geen teller om aan te maken, geen om op te hogen, en geen risico op een oneindige lus. Alleen de accumulator moet nog steeds buiten de lus beginnen, net als eerder.
Over een string lopen
for loopt niet alleen over getallen — het loopt ook over een string, teken voor teken:
word = "Python"
for letter in word:
print(letter, end="-")
print()
vowel_count = 0
for letter in "programming":
if letter in "aeiou":
vowel_count = vowel_count + 1
print("Vowels:", vowel_count)P-y-t-h-o-n-
Vowels: 3Hier is geen range nodig, want for letter in word loopt direct over de tekens. Dat is eenvoudiger dan met indexberekeningen, en je loopt niet het risico op een IndexError.
Als je zowel de index als het teken nodig hebt, is er enumerate(); dat komt in het hoofdstuk over lijsten.
break en continue werken hier ook
Precies zoals in een while:
for number in range(1, 20):
if number % 7 == 0:
print("First multiple of 7:", number)
breakFirst multiple of 7: 7Kiezen tussen for en while
Stel jezelf één vraag: is het aantal herhalingen bekend voordat de lus begint?
Zo ja, dan for:
- Vijf keer uitvoeren
- Van 1 tot 100 gaan
- Elk teken van een woord bekijken
- Iets doen met elk item in een lijst
Zo nee, dan while:
- Blijven vragen tot de invoer geldig is
- Doorgaan tot de persoon
quittypt - Lezen zolang er regels in een bestand staan
Twijfel je, kies dan for. De reden is simpel: een for-lus over een range of een vaste string is gegarandeerd af te ronden, en een while-lus niet. Als beide zouden werken, is de beste keuze degene die de minste ruimte laat voor fouten.
Een compleet voorbeeld
multiplication.py:
# Print a multiplication table, then a small summary
number = int(input("Which table? "))
upto = int(input("Up to? "))
print()
print(f"--- Table of {number} ---")
total = 0
for i in range(1, upto + 1):
result = number * i
total = total + result
print(f"{number} x {i:2} = {result:4}")
print()
print(f"Rows : {upto}")
print(f"Sum : {total}")
print(f"Average : {total / upto:.2f}")Which table? 7
Up to? 5
--- Table of 7 ---
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
Rows : 5
Sum : 105
Average : 21.00Drie dingen om op te letten. Ten eerste, range(1, upto + 1) — om upto te bereiken moest je er één bij schrijven. Ten tweede, {i:2} en {result:4} — binnen een f-string kun je aangeven hoeveel ruimte een getal mag innemen, zodat de kolommen netjes onder elkaar blijven. Ten derde begint total buiten de lus en groeit hij binnenin — dezelfde accumulator als eerder.
En stel jezelf één vraag: wat gebeurt er als iemand bij Up to? 0 invult? range(1, 1) levert helemaal geen getallen op, dus de lus draait nooit — en dan deelt total / upto door nul. Het is dezelfde les als in het vorige hoofdstuk: controleer, voordat je gebruikt wat een lus heeft opgebouwd, of er ook echt iets is opgeteld.
Wanneer het misgaat
Het laatste getal ontbreekt range(1, 10) eindigt bij 9. Tel er één bij op voor de stop: range(1, 11).
TypeError: 'float' object cannot be interpreted as an integer range() accepteert alleen hele getallen (int). range(2.5) of range(1, n / 2) werkt niet — zet het om met int(), of deel met //.
SyntaxError: expected ':' De dubbele punt aan het eind van de for-regel ontbreekt.
IndentationError: expected an indented block after 'for' statement De regel binnen de lus is niet ingesprongen.
De lus is helemaal niet uitgevoerd De range is leeg. range(5, 0) levert niets op — om af te tellen heb je het derde argument nodig: range(5, 0, -1).
Het totaal is 0 na de lus De regel total = 0 is per ongeluk in de lus terechtgekomen, waardoor hij elke ronde opnieuw wordt gezet. Hij moet erbuiten staan.
Een variabele uit de lus is buiten de lus nodig, maar geeft een NameError De range was leeg, dus de lus is nooit gedraaid en de variabele is nooit aangemaakt. Geef hem een startwaarde vóór de lus.
Stap 4 van 6 — Voorspellen
Test je begrip
Wat print deze lus?
for i in range(1, 5):
print(i, end=" ")- A1 2 3 4 5
- B1 2 3
- C0 1 2 3 4
- D1 2 3 4
Het derde argument bepaalt de stap. Wat is de uitvoer?
for i in range(0, 10, 3):
print(i, end=" ")- A3 6 9
- B0 3 6 9
- C0 1 2 3 4 5 6 7 8 9
- D0 3 6 9 12
De bedoeling was de som van 1 tot en met 10, dat is 55. Er wordt 45 geprint. Waarom?
total = 0
for number in range(1, 10):
total = total + number
print("Sum of 1 to 10:", total)- A`total` is buiten de lus op een startwaarde gezet, terwijl het binnen de lus hoort
- BEen `while`-lus gebruiken in plaats van `for` geeft het juiste antwoord
- CHet moet `total + i` zijn in plaats van `total + number`
- D`range(1, 10)` eindigt bij `9` en laat `10` weg — het moet `range(1, 11)` zijn
Voor antwoorden heb je een account nodig
Log in om je antwoorden te controleren
De vragen staan hierboven, en ze in je hoofd uitwerken is waar het om draait. Log in om de antwoorden, de uitleg en de hints in drie niveaus te zien.
Jouw beurt
Schrijf een bestand stars.py dat een getal inleest en een driehoek print. Bij invoer 5:
*
**
***
****
*****Voeg daarna deze drie dingen toe:
- Print onderaan het totale aantal sterretjes (15 bij invoer 5)
- Print de driehoek ook omgekeerd — vijf bovenaan, één onderaan
- Print een versie die de rijen met een even nummer overslaat (gebruik
continue)
Er is een makkelijke manier om de eerste te controleren — reken de som van 1 tot en met 5 met de hand uit en kijk of je programma het eens is. En weet je nog "*" * i? Voor het bouwen van een rij sterretjes heb je geen lus binnen de lus nodig.
Stap 6 van 6
Uitdaging — de hoofdstukquiz
Tien vragen van makkelijk naar moeilijk. De laatste zijn met opzet lastig.
Log in om de quiz te maken