Opstap

Deze pagina bevat uitvoerbare code.

Opdracht: Opstap

Bij de leesvragen is het antwoord de uitvoer van de code. Die code staat hieronder in een cel die opnieuw wordt uitgevoerd telkens als deze pagina wordt gemaakt. Wat je als uitvoer ziet staan is dus werkelijk wat Python doet, en niet wat iemand dacht dat Python doet.

Bij het debuggen ligt dat anders: die code is met opzet stuk en wordt daarom niet uitgevoerd. Daar staat de code als tekst, met eronder wat eraan mankeert.

Conditionele statements

Opdracht 1

x is 8 en dus groter dan 5: de if gaat aan. De laatste print staat buiten de if - je ziet het aan de inspringing - en gaat daarom altijd aan.

x = 8

if x > 5:
    print("if statement is True")
print("staat buiten de if statement")
if statement is True
staat buiten de if statement

Opdracht 2

x is 8 en dus niet kleiner dan 5: de if slaat over. Er is geen else, dus blijft alleen de regel buiten de if over.

x = 8

if x < 5:
    print("if statement is True")
print("staat buiten de if statement")
staat buiten de if statement

Opdracht 3

x is 8 en dus niet kleiner dan 5, dus gaat de else aan. Let op dat er false staat met een kleine letter: dat is gewoon tekst in een string, geen Python.

x = 8

if x < 5:
    print("if statement is True")
else:
    print("if statement is false")
print("staat buiten de if-else statement")
if statement is false
staat buiten de if-else statement

Opdracht 4

x is 5. Die is niet kleiner dan 5 en ook niet groter dan 5, dus vallen de if en de elif allebei af en blijft de else over.

x = 5

if x < 5:
    print("if statement is True")
elif x > 5:
    print("elif statement is True")
else:
    print("zowel de if en elif statements zijn false")
zowel de if en elif statements zijn false

Opdracht 5

temp is 23.0. Niet groter dan 35.0, wel groter dan 20.0. Bij een if-elif-keten stopt Python bij de eerste voorwaarde die waar is: de test op 10.0 wordt niet eens meer gedaan.

temp = 23.0

if temp > 35.0:
    print("Heet!")
elif temp > 20.0:
    print("Warm")
elif temp > 10.0:
    print("Koel")
else:
    print("Brrr!")
Warm

Opdracht 6

temp is 15.0. Niet groter dan 35.0, dus de else; daarbinnen niet groter dan 20.0, dus weer de else; daarbinnen wel groter dan 10.0.

Dit is dezelfde keten als opdracht 5, maar dan met geneste if-else in plaats van elif. Ze doen hetzelfde - en dat is precies de les: de elif-vorm zegt hetzelfde met minder inspringing.

temp = 15.0

if temp > 35.0:
    print("Heet!")
else:
    if temp > 20.0:
        print("Warm")
    else:
        if temp > 10.0:
            print("Koel")
        else:
            print("Brrr!")
Koel

Opdracht 7

x is 5: niet kleiner dan 5 en niet groter dan 5. Er is geen else, dus gaat er geen enkele tak aan en verandert x niet.

x = 5

if x < 5:
    x = x + 3
elif x > 5:
    x = x - 3
print(x)
5

Opdracht 8

x is 4 en dus kleiner dan 5, dus wordt x opgehoogd met 3. Daarna is x gelijk aan 7.

x = 4

if x < 5:
    x = x + 3
elif x > 5:
    x = x - 3
else:
    x = x * 2

print(x)
7

Opdracht 9

Strings vergelijk je alfabetisch. "Suzan" is groter dan "E", "J" en "O", maar niet groter dan "U" - de S komt voor de U.

naam = "Suzan"
if naam <= "E":
    print("groep 1")
elif naam <= "J":
    print("groep 2")
elif naam <= "O":
    print("groep 3")
elif naam <= "U":
    print("groep 4")
else:
    print("groep 5")
groep 4

Opdracht 10

Dit is de valkuil. Je zou "Emily" bij groep 1 verwachten, maar "Emily" <= "E" is onwaar: "E" is het begin van "Emily", en van twee strings waarvan de een het begin van de ander is, is de kórtste de kleinste. Dus "Emily" is groter dan "E", en de volgende test beslist.

naam = "Emily"
if naam <= "E":
    print("groep 1")
elif naam <= "J":
    print("groep 2")
elif naam <= "O":
    print("groep 3")
elif naam <= "U":
    print("groep 4")
else:
    print("groep 5")
groep 2

Strings en lijsten

Opdracht 11

a is een string, geen getal. Een string maal een getal herhaalt de string; er wordt niets opgeteld.

a = "123"
print(2 * a)
123123

Opdracht 12

Vermenigvuldigen gaat vóór optellen, ook bij strings: eerst wordt "hanze" verdubbeld, daarna komt "Hogeschool" erachter. Er komt geen spatie tussen - die moet je zelf plaatsen.

a = "hanze"
b = "Hogeschool"
print(2 * a + b)
hanzehanzeHogeschool

Opdracht 13

Hier wordt niets opgeteld maar afgedrukt. Een komma in print zet zelf een spatie tussen de twee waarden, en het maakt niet uit dat de een een getal is en de ander een string.

a = 123
b = "456"
print(a, b)
123 456

Opdracht 14

answer0 is p[0:3], dus [3, 1, 4]. answer1 is c[5], dus het getal 2 - één element, geen lijst. Een lijst maal een getal herhaalt de lijst.

p = [3, 1, 4, 1, 5]
c = [2, 9, 9, 7, 9, 2, 4, 5, 8]

answer0 = p[0:3]
answer1 = c[5]

print(answer0 * answer1)
[3, 1, 4, 3, 1, 4]

Opdracht 15

Zes slices achter elkaar geplakt, elk uit "computer" of "science". Een negatieve stapgrootte leest achteruit:

slice

levert

s[2:0:-1]

'ic'

c[5]

't'

s[2::-2]

'is'

s[0]

's'

c[4:2:-1]

'up'

c[6:]

'er'

Samen vormen ze een verborgen boodschap. Let op dat c[5] en s[0] geen slices zijn maar indices: die geven één teken, geen stukje string. answer0 en answer1 worden in de opgave wel gemaakt maar door de print niet gebruikt.

c = "computer"
s = "science"

answer0 = s[2:0:-1]
answer1 = c[5]

print(s[2:0:-1] + c[5] + s[2::-2] + s[0] + c[4:2:-1] + c[6:])
ictissuper

Opdracht 16

  1. len(pi) is 6

  2. len(lst) is 3

  3. len(lst[1]) is 5 - lst[1] is de string "isn't", en het apostrofteken telt gewoon mee

  4. pi[2:4] is [4, 1]

  5. pi[0:3] geeft [3, 1, 4]

  6. pi[0:5:2] geeft [3, 4, 5] - stapgrootte 2 slaat er telkens een over

pi = [3, 1, 4, 1, 5, 9]

lst = ['pi', "isn't", [4,2]]

print(len(pi), len(lst), len(lst[1]))
print(pi[2:4])
print(pi[0:3])
print(pi[0:5:2])
6 3 5
[4, 1]
[3, 1, 4]
[3, 4, 5]

Opdracht 17

  1. lst[0] is 'pi'

  2. lst[0][1] is 'i' - eerst het element uit de lijst, dan een teken uit die string

  3. lst[0:1] is ['pi'] - een slice van een lijst is zelf een lijst, ook als er één ding in zit. Vergelijk met vraag 1: daar krijg je de string zelf.

  4. string[9:15] is 'parent'

  5. string[::5] is 'Yeah cs!'

  6. string[31:34] geeft 'try'

  7. string[30:14:-4] geeft 'shoe' - achteruit, met stappen van 4. De getallen in het commentaar onder de string zijn daarbij de hint: ze staan precies onder de tekens 0, 4, 8 enzovoort.

lst = ["pi", "isn't", [4, 2]]

string = "You need parentheses for chemistry !"
#         0   4   8   12  16  20  24  28  32

print(lst[0], lst[0][1], lst[0:1])
print(string[9:15])
print(string[::5])
print(string[31:34])
print(string[30:14:-4])
pi i ['pi']
parent
Yeah cs!
try
shoe

Opdracht 18

  1. pi[0] * (pi[1] + pi[2]) is 15 - hier worden twee getallen opgeteld: 3 × (1 + 4)

  2. pi[0] * (pi[1:2] + pi[2:3]) is [1, 4, 1, 4, 1, 4] - hier worden twee lijsten aan elkaar geplakt tot [1, 4], en die wordt drie keer herhaald

  3. 3 * pi[0:5:2] geeft [3, 4, 5, 3, 4, 5, 3, 4, 5]

Vraag 1 en 2 verschillen alleen in de blokhaken, en dat is het hele punt: pi[1] is een getal, pi[1:2] is een lijst met dat getal erin.

pi = [3, 1, 4, 1, 5, 9]

print(pi[0] * (pi[1] + pi[2]))
print(pi[0] * (pi[1:2] + pi[2:3]))
print(3 * pi[0:5:2])
15
[1, 4, 1, 4, 1, 4]
[3, 4, 5, 3, 4, 5, 3, 4, 5]

Opdracht 19

  1. [4, 2] > [42] is False - lijsten worden element voor element vergeleken, en 4 is kleiner dan 42

  2. "hoi" > "doei" is True - de h komt na de d

  3. "eten" > "werken" is False - de e komt voor de w

  4. "Haard" < "Huis" is True - de eerste letter is gelijk, dus beslist de tweede: a komt voor u

  5. "F" < "Fiets" is True - "F" is het begin van "Fiets", en de kortste is de kleinste. Dit is dezelfde regel als bij opdracht 10

  6. [4, "m&m's"] < [1, "koffie"] is False - het eerste element beslist al: 4 is niet kleiner dan 1. Naar de strings wordt niet meer gekeken

print([4, 2] > [42])
print("hoi" > "doei")
print("eten" > "werken")
print("Haard" < "Huis")
print("F" < "Fiets")
print([4, "m&m's"] < [1, "koffie"])
False
True
False
True
True
False

Debuggen

Hieronder staat per uitwerking wat eraan mankeert. De code is met opzet stuk en wordt daarom niet uitgevoerd; hij staat als tekst.

Drie fouten lopen luid af - Python weigert de code te lezen en geeft een foutmelding. De andere vier lopen stil af: de code werkt, drukt een busnummer af, en dat nummer is gewoon verkeerd. Die tweede soort is de gevaarlijkste, en twee ervan geven bij naam = "Hoebe" zelfs het juiste antwoord. Om ze te betrappen heb je een andere naam nodig.

Waar hieronder staat hoe vaak een uitwerking de mist in gaat, is dat geteld met deze elf namen, één uit elk stukje van het alfabet:

Aalders, Bakker, Emmens, Jansen, Hoebe, Kramer, Oostra, Prins, Ubbens, Visser, Zijlstra

Je kunt ze zelf gebruiken om een stille fout te betrappen: vul een naam in, reken uit in welke bus hij hoort, en kijk of dat eruit komt.

Uitwerking A

if naam[0] <= 'E':
    print(1)
if naam[0] <= 'J':
    print(2)
if naam[0] <= 'O':
    print(3)
if naam[0] <= 'U':
    print(4)
else
    print(5)

Luid: SyntaxError op de laatste else. Daar ontbreekt de dubbele punt.

Maar er zit een tweede fout onder, die pas zichtbaar wordt als je de dubbele punt erbij zet: dit zijn vier losse if-statements in plaats van één keten. Elke test wordt apart uitgevoerd, dus een naam als "Bakker" gaat door de eerste vier heen en drukt 1, 2, 3 en 4 af. En de else hoort alleen bij de laatste if.

Uitwerking B

if naam[0] >= 'E':
    print(1)
elif naam[0] >= 'J':
    print(2)
elif naam[0] >= 'O':
    print(3)
elif naam[0] >= 'U':
    print(4)
else:
    print(5)

Stil: de vergelijkingen staan de verkeerde kant op. Er staat >= waar <= hoort.

Daardoor is de eerste test bijna altijd waar en gaat vrijwel iedereen naar bus 1. Van elf voorbeeldnamen gaan er tien naar de verkeerde bus: "Aalders" naar 5 in plaats van 1, "Hoebe" naar 1 in plaats van 2.

Uitwerking C

if naam[0] <= 'E':
    print(1)
else:
    if naam[0] <= 'J':
        print(2)
    elif naam[0] <= 'O':
        print(3)
        if naam[0] <= 'U':
            print(4)
        else:
            print(5)

Stil: de inspringing klopt niet. De test op 'U' staat binnen de tak van elif naam[0] <= 'O', in plaats van ernaast.

Dat geeft twee verschillende fouten tegelijk. Namen van K tot en met O doorlopen eerst de elif (die drukt 3 af) en daarna ook de geneste test, zodat er twee nummers verschijnen. Namen vanaf P komen door geen enkele tak en krijgen helemaal geen bus.

Bij naam = "Hoebe" gaat dit goed - die valt in de geneste if op 'J' en merkt er niets van. Probeer "Kramer" of "Prins" om de fout te zien; van de elf namen gaan er zes mis.

Uitwerking D

if naam[0] <= 'E':
    print(1)
elif naam[0] <= 'J':
    print(2)
    elif naam[0] <= 'O':
        print(3)
    elif naam[0] <= 'U':
        print(4)
    else:
        print(5)

Luid: SyntaxError op de tweede elif, die op 'O'. Die is ingesprongen, en daarmee staat hij binnen de tak van de elif erboven in plaats van ernaast.

Een elif hoort altijd op dezelfde hoogte als de if waar hij bij hoort.

Uitwerking E

if naam[0] <= 'Z':
    print(5)
elif naam[0] <= 'U':
    print(4)
elif naam[0] <= 'O':
    print(3)
elif naam[0] <= 'J':
    print(2)
else:
    print(1)

Stil: de keten staat in de verkeerde volgorde. De ruimste test staat vooraan.

Bijna elke achternaam is kleiner dan of gelijk aan 'Z', dus gaat de eerste tak vrijwel altijd aan en komt iedereen in bus 5. Bij een if-elif-keten stopt Python bij de eerste voorwaarde die waar is, dus de rest wordt nooit bekeken. Negen van elf voorbeeldnamen gaan mis.

Uitwerking F

if naam <= 'E':
    print(1)
elif naam <= 'J':
    print(2)
elif naam <= 'O':
    print(3)
elif naam <= 'U':
    print(4)
else:
    print(5)

Stil, en het subtielst van allemaal: er staat naam waar naam[0] hoort. Er wordt dus de hele achternaam vergeleken in plaats van alleen de eerste letter.

Meestal gaat dat toevallig goed, en bij naam = "Hoebe" ook. Het gaat alleen mis bij namen die met de grensletter zelf beginnen, en dan om dezelfde reden als bij opdracht 10: "Jansen" <= "J" is onwaar, want "J" is het begin van "Jansen" en de kortste is de kleinste. "Jansen" komt daardoor in bus 3 in plaats van 2. Hetzelfde geldt voor "Emmens", "Oostra" en "Ubbens" - vier van elf.

Uitwerking G

if naam < 'F'
    print(1)
elif naam < 'K'
    print(2)
elif naam < 'P'
    print(3)
elif naam < 'V'
    print(4)
else:
    print(5)

Luid: SyntaxError op de eerste regel. Achter if en achter elke elif ontbreekt de dubbele punt; alleen de else heeft er een.

En dat is de enige fout. Dat is opmerkelijk, want uitwerking G vergelijkt de hele naam en niet naam[0] - precies wat bij uitwerking F de boosdoener was. Hier kan dat wel, en de reden is de vorm van de grens: er staat < 'F' en niet <= 'E'. De valkuil van opdracht 10 ontstaat doordat "Jansen" <= "J" onwaar is, maar "Jansen" < "K" is gewoon waar - elke naam die met een J begint is kleiner dan "K", hoe lang hij ook is. Met een grens die de vólgende letter uitsluit, verdwijnt het lengteprobleem.

Met de dubbele punten erbij geeft uitwerking G dus bij alle elf namen het juiste busnummer.

En hoe hoort het dan wel?

Alle zeven zijn een poging tot dezelfde keten. Zo ziet die er heel uit:

naam = "Hoebe"

if naam[0] <= "E":
    print(1)
elif naam[0] <= "J":
    print(2)
elif naam[0] <= "O":
    print(3)
elif naam[0] <= "U":
    print(4)
else:
    print(5)
2

Vijf dingen zijn hier van belang, en de zeven kapotte versies laten er samen elk een weg:

  1. Het is één keten met elif, en geen reeks losse if-statements (uitwerking A).

  2. De vergelijkingen staan de goede kant op (uitwerking B).

  3. Elke tak staat op dezelfde hoogte als de if waar hij bij hoort - niet ingesprongen, en niet genest (uitwerking C en D).

  4. De nauwste grens staat vooraan (uitwerking E).

  5. Er wordt naar naam[0] gekeken en niet naar naam (uitwerking F).

Uitwerking G komt in dat rijtje niet voor: die maakt geen van deze vijf fouten en mist alleen zijn dubbele punten.