Programmaverloop en variabelen

Inleiding

In dit hoofdstuk leer je twee belangrijke concepten binnen het programmeren. Het eerste concept is het programmaverloop, ofwel de volgorde waarin instructies in het programma worden uitgevoerd. Die volgorde bepaal je op basis van bepaalde voorwaarden. Simpel gezegd: "Als dit, dan dat." De volgorde kun je ook bepalen op basis van herhaling: voer een instructie uit totdat aan een voorwaarde (niet meer) is voldaan.

Het tweede concept dat je in dit hoofdstuk leert, is de variabele. Je bent variabelen al een paar keer tegengekomen. Na het lezen van dit hoofdstuk zul je ze niet alleen gebruiken, maar ook begrijpen.

Leerdoelen

Aan het einde van dit hoofdstuk:

  • Begrijp je hoe je if, elif en else gebruikt om het programmaverloop te bepalen

  • Begrijp je hoe je while gebruikt om het programmaverloop te bepalen

  • Begrijp je wat een variabele is en wat een referentie is

  • Begrijp je wat een object is

  • Begrijp je hoe muteren van objecten werkt

Programmaverloop met if/elif/else en while

In een gemiddeld programma worden ontelbaar veel keuzes gemaakt. Als de gebruiker op "Opslaan" klikt, sla dan het bestand op. Als de gebruiker op "Annuleer" klikt, ga dan terug. Laat alle taken in de todo-app zien. Als ze zijn afgevinkt, markeer ze dan doorgestreept. Als ze het label "Urgent" hebben, markeer ze dan rood. Enzovoorts.

In deze paragraaf leer je de if-elif-else-statement, waarmee je dergelijke keuzes kunt programmeren. Ook leer je over de while-statement, waarmee je code uitvoert zolang een gegeven waar is.

Als, anders

In de paragraaf Relationele operatoren in Eerste stappen leerde je dat je booleans (True en False) vaak zult gebruiken om het programmaverloop te beïnvloeden. Je zag daar de volgende code:

x = 20  # Wijs de waarde 20 toe aan de variabele x

if x > 20:
    print("X is groter dan 20!")
else:
    print("X is 20 of kleiner!")

Dergelijke if-else-clausules zijn één van de manieren om het verloop van je programma te bepalen. Je neemt een expressie[1] - in dit geval x > 20 - en als die waar is voer je de code in het if-blok uit. Is de expressie niet waar, dan ga je verder naar het else-blok en voer je die code uit.

De algemene structuur is:

if expressie is waar:
    doe iets
else:
    doe iets anders

In dit geval is de expressie x > 20 niet waar. Het blok op regel vier wordt dus niet uitgevoerd. Je komt daarmee in de volgende clausule terecht, op regel vijf. De else-clausule betekent simpelweg: "In alle andere gevallen". Hier geldt net als bij de if-clausule dat je de regel eindigt met een dubbele punt, en dat het blok op de regels erna uitgevoerd wordt.

In Eerste stappen lees je nog eens terug hoe het ook alweer zit met blokken en inspringen.

Als/dan statements zijn niet alleen nuttig bij het vergelijken van getallen, maar bij alles wat een bool oplevert. Enkele voorbeelden:

# Controleer of een stuk fruit in de lijst voorkomt met `in`
fruit = ['appel', 'banaan', 'sinaasappel']
if 'appel' in fruit:
    print("Appel aanwezig in de lijst van fruit")


# Controleer of twee objecten gelijk zijn met `is`
a = [1, 2, 3]
b = a
if a is b:
    print("a en b verwijzen naar hetzelfde object")
Else is optioneel

In de voorbeelden zie je dat je else niet altijd hoeft te gebruiken. Hiermee zeg je eigenlijk: "Als waar, doe iets. Zo niet, ga verder met het programma.".

# `is` gebruik je ook om te controleren of een variable de waarde `None` heeft
x = 1
if x is None:
    print("x is None")  # Zal niet worden uitgevoerd

print("x is niet None. Het programma gaat hier verder.")

En, Of

Vaak wil je het programmaverloop bepalen op basis van meerdere voorwaarden, bijvoorbeeld als twee expressies waar zijn. Dit doe je met and:

x = 5
y = 10
if x > 3 and y > 5:
    # Beide zijn waar, dus dit blok wordt uitgevoerd
    print("x is groter dan 3 EN y is groter dan 5")
else:
    print("Eén van beide expressies is niet waar")

Als je and gebruikt, zeg je dat beide expressies waar moeten zijn om de gehele expressie waar te laten zijn. Dus alleen als x groter is dan drie én y groter is dan vijf wordt regel vier uitgevoerd. Als één van de twee niet waar is, kom je in de else-clausule terecht.

Let hierbij op dat Python het zogenaamde short-circuit principe hanteert. Als het eerste argument (x > 3 in dit geval) False is, gaat Python direct door naar de else-clausule. Het tweede argument (y > 5) wordt dan niet meer bekeken.

Het kan ook voorkomen dat je iets wilt doen als van meerdere vergelijkingen er minstens één waar is. Dit doe je met or:

x = 5
y = 3
if x > 3 or y > 5:
    # Eén van beide is waar, dus dit blok wordt uitgevoerd
    print("x is groter dan 3 OF y is groter dan 5")
else:
    print("Beide expressies zijn niet waar")

Let op, met or test je of tenminste één van de opgegeven expressies waar is. Als alle expressies waar zijn, is er dus tenminste één waar, en zal het blok worden uitgevoerd:

x = 5
y = 10
if x > 3 or y > 5:
    # Beide zijn waar, dus dit blok wordt uitgevoerd
    print("x is groter dan 3 OF y is groter dan 5")
else:
    print("Beide expressies zijn niet waar")

Ook hier geldt weer dat het short-circuit principe geldt. Als het eerste argument (x > 3) True is, wordt het blok direct uitgevoerd (één van de twee is immers waar). Het tweede argument (y > 5) wordt niet meer bekeken.

Opdracht 1: Alarm

Schrijf een eenvoudig alarmsysteem voor een ruimte met twee deuren. Neem aan dat het alarm aan staat. Als er een deur open staat, laat dan het alarm afgaan.

Klik om het antwoord te tonen

Een mogelijke uitwerking is als volgt:

voordeur_open = False
achterdeur_open = True

if voordeur_open or achterdeur_open:
    print("Alarm! Een deur is open!")
else:
    print("Alles is veilig. Alle deuren zijn gesloten.")

Als, anders-als, anders

Tot nu toe zag je de structuur: "Als waar, doe iets. Anders…​". Maar er is nog een mogelijkheid om je programmaverloop te bepalen.

leeftijd = 83
if leeftijd < 4:
    toegangsprijs = 0
elif leeftijd < 65:
    toegangsprijs = 40
else:
    toegangsprijs = 20

print(f"Je toegangsprijs is €{toegangsprijs}.")

Hier test je eerst of leeftijd kleiner is dan vier. Als dat niet zo is, zoals in het voorbeeld, kom je in de volgende clausule. Dit is elif, kort voor else-if. Hier test je of leeftijd kleiner is dan 65. Als dit ook niet waar is, dan ga je naar de else-clausule.

Opdracht 2: €40

Welke waarde moet je leeftijd geven om de toegangsprijs €40 te laten zijn?

Klik om het antwoord te tonen

Als je leeftijd een waarde vanaf 4 tot 65 (maar geen 65), dan is de toegangsprijs €40.

Je kunt in een else-elif-else-blok meerdere elif-clausules gebruiken:

leeftijd = 83
if leeftijd < 4:
    toegangsprijs = 0
elif leeftijd < 18:
    toegangsprijs = 25
elif leeftijd < 65:
    toegangsprijs = 40
else:
    toegangsprijs = 20

print(f"Je toegangsprijs is €{toegangsprijs}.")

Let hierbij op dat de code altijd van boven naar beneden wordt uitgevoerd. De eerste expressie die waar is, wordt uitgevoerd, en de if-elif-else-ketting zal daarna zijn afgerond. Dit betekent dat als je meerdere elif-statements hebt die waar zijn, alleen de eerste wordt uitgevoerd. Kortom: er wordt altijd maar één blok uitgevoerd uit een if-elif-else-ketting. Net als bij een if-else-statement, overigens.

leeftijd = 17
if leeftijd < 4:
    toegangsprijs = 0
elif leeftijd < 18:  # Waar
    toegangsprijs = 25
elif leeftijd < 65:  # Ook waar, maar nooit uitgevoerd
    toegangsprijs = 40
else:
    toegangsprijs = 20

print(f"Je toegangsprijs is €{toegangsprijs}.")
Opdracht 3: Verkeerslicht

Hoe zou je met if-elif-else een verkeerslicht vormgeven? Gebruik de variabele actie voor de actie die het voertuig voor het verkeerslicht moet uitvoeren bij elke kleur (rood, oranje, groen).

Klik om het antwoord te tonen

Een mogelijke uitwerking is:

licht = ""
actie = None

if licht == "rood":
    actie = "stoppen"
elif licht == "oranje":
    actie = "stoppen als het lukt"
elif licht == "groen":
    actie = "doorrijden"
else:
    actie = "wachten op een verkeersleider, de verkeerslichten zijn kapot"

print(f"Het voertuig moet {actie}.")

While

Naast if-elif-else is er nog een manier om het programmaverloop te bepalen op basis van expressies die een bool opleveren. Met while voer je iets uit zolang iets waar is.

# Eenvoudig voorbeeld
huidig_getal = 1
while huidig_getal <= 10:
    print(huidig_getal)
    huidig_getal += 1

Op regel 1 begin je met tellen door de waarde 1 toe te wijzen aan de variabele huidig_getal. Op regel 2 stel je in dat de while-loop blijft draaien zolang huidig_getal 10 of kleiner is. Zodra huidig_getal 11 wordt, is de expressie niet meer waar en breekt de loop af.

De code in de loop print op regel drie het huidige getal. Op regel vier wordt het huidige getal met één opgehoogd (huidig_getal += 1 is een korte manier om huidig_getal = huidig_getal + 1 te schrijven). Na regel vier is de loop klaar en begint het opnieuw, zolang huidig_getal <= 10 waar is.

Loops

In Eerste stappen heb je al kort de for-loop behandeld. Zowel for als while gebruik je om een stuk code meerdere malen uit te voeren. Het verschil zit in de manier waarop wordt bepaald hoe vaak de code wordt uitgevoerd.

Bij een for-loop wordt de code voor elk element in een reeks uitgevoerd (itereren). Bij een while-loop wordt de code uitgevoerd zolang de opgegeven expressie waar is (of je de loop met break stopt.).

Een while-loop gebruik je om continue iets uit te voeren tot een bepaalde conditie is bereikt. Een voorbeeld is om een programma net zo lang te laten draaien totdat de gebruiker vertelt om het te stoppen.

# User input
instructie = "Vertel me iets, en ik herhaal het voor je. " \
         "Typ 'exit' om te stoppen. "
bericht = ""

while bericht != "exit":
    bericht = input(instructie)
    print(bericht, "\n")

In bovenstaande code vraag je de gebruiker om input met input(instructie) (de instructie is op regel één gedefinieerd). Zolang de gebruiker geen 'exit' typt, zal het programma het bericht printen en opnieuw om input vragen.

Opdracht 4: Papegaai

Als de gebruiker 'exit' typt, print het programma dit ook voordat het stopt. Hoe zorg je ervoor dat dit niet het geval is?

Klik om het antwoord te tonen

Als je 'exit' niet wilt printen, kun je dit voorkomen met een if-statement:

while bericht != "exit":
    bericht = input(instructie)
    if bericht != "exit":
        print(bericht, "\n")

Een alternatieve manier om een loop te stoppen is met de break-statement.

while True:
    bericht = input(instructie)
    if bericht == "exit":
        break

    print(bericht, "\n")

Je ziet dat regel een begint met while True, ofwel: de conditie is altijd waar en de loop zal dus oneindig draaien. Op regel drie en vier zie je: als het bericht 'exit' is, 'breek' dan uit de loop. Regel zes zal in dat geval dus niet uitgevoerd worden.

Het tegenovergestelde van break is continue. Met continue vertel je de code dat je de huidige iteratie[2] van de loop wilt afbreken en terug wil naar het begin van de loop, zonder de code eronder uit te voeren. Waar je met break dus de hele loop stopt, zorg je er met continue voor dat de huidige ronde stopt, maar de loop als geheel wel door blijft gaan.

while True:
    bericht = input(instructie)
    if bericht == "Python is stom":
        continue

    if bericht == "exit":
        break

    print(bericht, "\n")

De break is verplaatst naar regel zes en zeven. Op regel drie en vier zorg je ervoor dat als een gebruiker 'Python is stom' typt, de loop opnieuw begint. De code eronder wordt niet uitgevoerd, en het bericht wordt niet geprint (en terecht!).

De break en continue statements werken in een while-loop, maar ook binnen een for-loop.
Mocht je ooit in de situatie komen dat je per ongeluk een oneindige loop hebt gemaakt, zonder optie om het te stoppen, dan kun je in de shell op ctrl en c drukken, het programma stopt dan. Je kunt uiteraard ook simpelweg de shell afsluiten.
Opdracht 5: Hoogste getal

Schrijf een Python-programma dat de gebruiker vraagt om een getal in te voeren. Het programma moet blijven vragen om getallen tot de gebruiker "stop" intypt. Wanneer "stop" wordt ingevoerd, moet het programma het hoogste ingevoerde getal afdrukken.

Klik om het antwoord te tonen

Een voorbeelduitwerking is:

hoogste_getal = 0  # Begin bij 0

while True:
    # Vraag de gebruiker om een getal en sla het op
    invoer = input("Voer een getal in. Typ 'stop' om te stoppen.\n Invoer: ")

    # Als de invoer 'stop' is, druk het hoogste getal af en stop de while-loop
    if invoer == "stop":
        print(hoogste_getal)
        break

    # Invoer is altijd tekst, zet om naar int en vergelijk met het huidige
    # hoogste getal. Als de invoer hoger is, sla het op in hoogste_getal
    if int(invoer) > hoogste_getal:
        hoogste_getal = int(invoer)

Variabelen

In voorgaande stof ben je al een aantal keer variabelen tegengekomen, de meeste voorbeelden maken gebruik van één of meer variabelen. Uit de voorbeelden blijkt al wat je met variabelen kunt: je koppelt ze aan waarden om ze later te gebruiken. In deze paragraaf ga je dieper in op variabelen, zodat je goed begrijpt wat een variabele écht is en hoe ze precies werken.

Labels

In Python wordt data vertegenwoordigd door objecten. Elk object heeft een ID, een type en een waarde. Als een object eenmaal is aangemaakt, verandert het ID niet meer. Je kunt het zien als het adres in het geheugen van de computer.

Alles is een object

In feite is alles een object in Python, dus niet bijvoorbeeld alleen de string "Python", maar ook een functie.

Het ID van een object haal je op met id(). Het type haal je op met type(). Met is vergelijk je of twee objecten hetzelfde ID hebben (en dus naar dezelfde plek in het geheugen verwijzen).

In Python gebruik je variabelen om te verwijzen naar objecten, en daarmee naar de waarde.

Als je het volgende uitvoert: x = 42 gebeurt er eigenlijk het volgende:

  1. Er wordt een object aangemaakt in het geheugen met een ID, het type int en de waarde 42.

  2. Er wordt een label (de variabele) aangemaakt, die verwijst naar dit object.

Voer je nu id(x) uit, dan vraag je dus feitelijk het ID op van het object waar x naar verwijst.

Zie het als een kast met verschillende laden. In elke lade stop je iets, sokken in de eerste, broeken in de tweede, etc. De kast is het geheugen, de lades zijn specifieke locaties in het geheugen en de sokken zijn de objecten (met de waarde 'Blauw' en het type 'Sok').

Om de objecten te gebruiken - je wilt je sokken aantrekken - is het nodig om ze te vinden. Daarom heb je een label op elke la geplakt. Een label toewijzen aan een object doe je met het =-teken. In het hoofdstuk Eerste stappen las je al dat Python een dynamisch getypeerde taal is, wat ervoor zorgt dat je bij het toewijzen van een variabele geen type hoeft op te geven.

sokken = "10 paar sokken"  # str
broeken = "3 broeken"  # str
geld = 1000  # int
lege_lade = None  # Lege lade

Het is belangrijk om variabelen zinvolle namen te geven die de opgeslagen gegevens of hun doel in de code beschrijven. Dus de x, y en z die je in de voorbeelden vaak ziet, mógen wel maar zijn in de praktijk niet handig. Er zijn een aantal regels voor naamgeving:

  • Variabelen moeten beginnen met een letter (a-z, A-Z) of een underscore (_).

  • Ze kunnen bestaan uit letters, cijfers en underscores, maar geen spaties.

  • Ze zijn hoofdlettergevoelig, wat betekent dat leeftijd en Leeftijd twee verschillende variabelen zijn.

Daarnaast zijn er nog conventies - geen harde regels, maar in de praktijk is het wel goed om je eraan te houden:

  • Gebruik kleine letters en underscores (ook wel 'snake_case' genoemd). Bijvoorbeeld: aantal_dagen, start_tijd.

  • Gebruik geen gereserveerde keywords, zoals if, while, class, en import. Gebruik deze woorden niet als variabelenamen om verwarring en fouten te voorkomen.

  • Gebruik constanten in hoofdletters. Als je een variabele hebt die een constante waarde vertegenwoordigt en niet mag worden gewijzigd, schrijf dan de variabelenaam in hoofdletters en scheid de woorden met underscores. Bijvoorbeeld: MAX_AANTAL.

Naast conventies voor de schrijfwijze van variabelen zijn er vele andere conventies. Eerder las je al over het inspringen met vier spaties, bijvoorbeeld. Al deze conventies lees je terug in 'PEP 8 - Style Guide for Python Code' (peps.python.org/pep-0008/).

Zodra een object een label heeft gekregen - zodra je een variabele hebt aangemaakt dus - kun je het gebruiken in je programma. Dit kan eenmalig, maar ook vaker.

print(f"In lade 1 vind je {sokken}. In lade 2 vind je {broeken}.")
print(f"Maar nu heb ik alleen {sokken} nodig.")  # `sokken` nogmaals gebruikt

Als je een variabele hebt toegewezen aan een object, is dit niet voor altijd. Je kunt de verwijzing eenvoudig wijzigen naar een ander object.

sokken = "8 paar sokken"  # Was "10 paar sokken"
print(f"In lade 1 vind je {sokken}. In lade 2 vind je {broeken}.")

Het hoeft zelfs niet van hetzelfde type te zijn:

sokken = 1000  # van str naar int
print(f"In lade 1 vind je {sokken} sokken. In lade 2 vind je {broeken}.")

print(type(sokken))  # <class 'int'>
Objecten, verwijzingen en mutaties

Als je de code bekijkt dan lijkt het net of je de waarden toewijst aan een variabele, en zo zul je er in de praktijk ook vaak over denken. Toch is het belangrijk om te onthouden dat een variabele een verwijzing is naar een object die een waarde bevat. Het object met waarde 1000 is ergens opgeslagen in het geheugen van je computer en vervolgens verwijs je er naar met een label.

Neem bijvoorbeeld een object van het type str met de waarde "10 paar sokken". Doe je nu in de code het volgende:

sokken = "10 paar sokken"  # str

Dan maakt Python eerst het object "10 paar sokken" van het type str aan. Vervolgens maakt Python de objectreferentie (label) sokken aan en zorgt ervoor dat sokken naar het object van type str met waarde "10 paar sokken" verwijst. In de praktijk zul je zeggen sokken is van het type str, maar feitelijk is het object waar sokken naar verwijst (de zin "10 paar sokken") van het type str.

Deze werkwijze heeft als gevolg dat twee variabelen naar hetzelfde object kunnen verwijzen.

x = 5
y = x

print(x is y)
print(id(x))
print(id(y))

Bij mutable variabelen betekent dit daardoor ook dat als je de waarde wijzigt via de ene variabele, de waarde voor de andere variabele ook wijzigt.

x = [1, 2, 3]
y = x

x[0] = 9
print(y)

Bekijk de eerste drie segmenten van deze video voor een gevisualiseerde uitleg.


1. Een expressie is in Python code dat een waarde oplevert. Dus: x > 20 is een expressie (levert `True` of `False` op. Maar een functie kan ook een expressie zijn, net als 1 + 1.
2. Itereren is het één voor één doorlopen van items in een collectie (zoals een list, tuple, dictionary)