1.1 Uitdrukkingen en functies

Wat Python uitrekent, en hoe je er zelf iets aan toevoegt

OpmerkingLeerdoelen

Na deze les kan je:

  • voorspellen welke waarde een uitdrukking heeft
  • een ingebouwde functie aanroepen en haar argumenten aanwijzen
  • zelf een functie schrijven met def en return
  • uitleggen waarom print en return niet hetzelfde zijn
  • de regels die Python stelt aan namen, indentatie en commentaar toepassen

In deze les schrijf je je eerste Pythoncode. Een computer doet uit zichzelf niets. Voor elke taak is er een programma nodig, dat bestaat uit blokken met instructies.

BelangrijkBelangrijk
  • Instructies worden van boven naar beneden uitgevoerd en regel per regel.
  • Uitdrukkingen met haakjes worden in Python van binnen naar buiten berekend.
  • Een eenvoudig programma doet altijd één bewerking tegelijk.

We beginnen bij wat de waarde is van een uitdrukking en eindigen bij functies die je zelf schrijft. Waarden bijhouden onder een naam komt volgende les. Experimenteer gerust met de code in de cellen.

1 Een uitdrukking en haar waarde

Een uitdrukking is een stukje code met een waarde. 3 + 4 is een uitdrukking, en haar waarde is 7. Wiskundige bewerkingen verlopen zoals je ze kent (op een aantal randgevallen na). Merk op dat sommige bewerkingen andere tekens gebruiken dan je gewend bent.

bewerking teken voorbeeld
optellen + 12 + 5 geeft 17
aftrekken - 12 - 5 geeft 7
vermenigvuldigen * 12 * 5 geeft 60
delen / 12 / 5 geeft 2.4
gehele deling // 12 // 5 geeft 2
rest % 12 % 5 geeft 2
macht ** 12 ** 2 geeft 144

2 Ingebouwde functies

Python heeft ingebouwde functies die altijd beschikbaar zijn. Een functie gebruiken heet ze aanroepen: je schrijft haar naam, gevolgd door de argumenten tussen haakjes. Zo geeft abs(-7) het getal 7, max(3, 9) het getal 9, round(2.71) het getal 3, en len("informatica") het aantal tekens 11.

De schrijfwijze van functies in Python is als volgt:

wiskunde Python
\(f(x)\) f(x)
\(f(x, y)\) f(x, y)
\(f(g(x))\) f(g(x))
\(2 f(x)\) 2 * f(x)
\(f(x) \, g(y)\) f(x) * g(y)

De eerste drie regels zijn identiek. Het verschil zit in de laatste twee: bij Python moet je altijd expliciet het maalteken schrijven. Wie 2f(x) of 2(x + 1) schrijft, krijgt een foutmelding.

3 Zelf een functie maken

Stel dat je op tien plaatsen in een programma dezelfde berekening schrijft. Dan moet je een aanpassing tien keer opnieuw doen. Een functie legt een gewenste berekening één keer vast onder een naam. Vervolgens kan je die functie onbeperkt hergebruiken door ze aan te roepen met haar naam en argumenten. Moet je toch nog iets aan de berekening aanpassen, dan hoeft dat meestal maar op één plaats, namelijk in de functiedefinitie.

Dat het woord hetzelfde is als in de wiskunde, is geen toeval. Wat je daar schrijft als

\[ f : \mathbb{R} \to \mathbb{R} : x \mapsto x^2 \]

schrijf je in Python bijvoorbeeld zo.

Laten we deze functie meteen een duidelijkere naam geven.

Alles wat geïndenteerd onder de def-regel staat, vormt het lichaam. Achter return staat het resultaat, namelijk wat de functie teruggeeft.

De parameter x is de naam waaronder de functie haar invoer kent en de naam die je gebruikt in de functiedefinitie. Aanroepen gebeurt door substitutie van de parameter door een argument, precies zoals je bij \(f(3)\) de \(x\) door \(3\) vervangt. Bij kwadraat(3) komt overal waar x staat het getal 3, waardoor 3 * 3 berekend wordt en er 9 wordt teruggegeven.

Een aanroep mag in een andere aanroep staan, net zoals \(f(f(x))\), en dan is de binnenste eerst aan de beurt om uit te rekenen. Bij kwadraat(kwadraat(3)) levert de binnenste aanroep 9 op, waarna kwadraat(9) het antwoord 81 geeft.

Een functiedefinitie kan naast ingebouwde functies ook je eigen functies bevatten. kubiek(3) geeft 27 als antwoord.

4 Tonen versus teruggeven

In het vorige onderdeel werkte kwadraat(kwadraat(3)), omdat de binnenste aanroep het getal 9 aflevert op de plaats waar ze staat. Die 9 kan dan worden gebruikt als argument voor de buitenste kwadraat.

Vervang je return door print, dan toont de functie het getal enkel op het scherm en komt er op de plaats van de aanroep niets terecht.

Roep je ze in een codecel los aan, dan verschijnt in beide gevallen 9. Het verschil blijkt zodra je met het resultaat verder wil. De cel hieronder bevat twee print-regels: hoeveel regels verschijnen er volgens jou, en wat staat erop?

De eerste regel levert 10. kwadraat(3) geeft het getal 9 terug op de plaats van de aanroep, er komt 1 bij, en print toont de som.

De tweede regel toont eerst 9 en loopt daarna vast. Python rekent het argument als eerste uit, dus toon_kwadraat(3) zet die 9 op het scherm met print, en geeft vervolgens niets terug. Een functie zonder return geeft None terug, de waarde die Python hanteert voor “hier is niets”. Bij None kan je niets optellen en dat staat er ook: unsupported operand type(s) for +: 'NoneType' and 'int'.

WaarschuwingOpgelet

Gebruik return als het resultaat nodig is voor verdere stappen in de berekening en print enkel wanneer je een waarde wil zien, hetzij in een tussenstap ter controle, hetzij als resultaat van de berekening.

5 Namen, blokken en commentaar

BelangrijkBelangrijk

Een naam in Python bestaat uit letters, cijfers en liggende streepjes, mag niet met een cijfer beginnen, en maakt onderscheid tussen hoofd- en kleine letters.

Kwadraat en kwadraat zijn dus twee verschillende namen. Kies beschrijvende namen, want inhoud_kegel vertelt een lezer meer dan f. De gewoonte is dat we namen met meer woorden in kleine letters schrijven met liggende streepjes ertussen, dus aantal_leerlingen en niet AantalLeerlingen.

De meest courante stijlen zijn kebab-case, snake_case en camelCase. In Python heeft men dus voor snake_case gekozen.

Een korte naam als x of n is bruikbaar voor een getal zonder verdere betekenis, zoals de parameter van een wiskundige functie.

Een aantal woorden is voorbehouden aan de taal zelf en kan je niet als naam gebruiken. Je kent er al twee, def en return. Andere, zoals if, else, while en import volgen nog.

Python bepaalt met indentatie wat bij een functie hoort. Alle regels die even ver geïndenteerd staan, vormen samen één blok. Verandert de indentatie, dan verandert de betekenis van je programma. De officiële Python stijlgids zegt vier spaties per niveau. Op kleine schermen kan twee spaties handiger zijn. Je kan in de meeste programmeeromgevingen de indentatie automatiseren.

Alles achter een hekje # is commentaar. Dit telt niet als code. Het dient om aan een lezer, jezelf inbegrepen, informatie te geven over de code.

6 Conclusie

De kleinste bouwsteen van een programma is de uitdrukking, een stukje code met een waarde. Een functie geeft een naam aan een berekening die je wil hergebruiken: je roept ze aan met argumenten, ze geeft een waarde terug met return, en die waarde kan meteen dienen in een volgende aanroep. Het kan ook zijn dat een functie niets teruggeeft, bijvoorbeeld enkel iets toont met print. In dat geval geeft de functie None terug.

Naamgeving in Python volgt vaste regels, bijvoorbeeld dat de naam van een functie wel cijfers mag bevatten, maar er niet mee mag starten. De structuur van Pythoncode heeft betekenis. Blokken bepalen met behulp van indentatie wat er bij elkaar hoort.

Alles wat je tot hier schreef, wordt uitgerekend, teruggegeven en meteen vergeten. In de volgende les leer je een waarde bijhouden onder een naam. Pas door nieuwe functies te schrijven met oude en door waarden bij te houden, door te geven en te hergebruiken, kan een programma iets betekenisvols opbouwen.

7 Begrippen

  • programma (program): een voorschrift waarin precies vastligt wat er moet gebeuren.
  • uitdrukking (expression): een stukje code met een waarde, zoals 3 + 4.
  • functie (function): een berekening die onder een naam vastligt en die je met argumenten aanroept.
  • aanroepen (to call): een functie gebruiken door haar naam te schrijven, gevolgd door de argumenten tussen haakjes.
  • parameter (parameter): de naam waaronder een functie haar invoer kent.
  • argument (argument): de waarde die je bij een aanroep meegeeft.
  • lichaam (body): alles wat geïndenteerd onder de def-regel staat en dus bij de functie hoort.
  • tonen (to print): een waarde op het scherm zetten met print, waar het programma zelf niets aan heeft.
  • teruggeven (to return): een waarde afleveren op de plaats van de aanroep, met return.
  • resultaat (return value): de waarde die zo afgeleverd wordt. Ook wel de terugkeerwaarde genoemd.
  • None: de waarde die Python teruggeeft wanneer er niets terug te geven valt. In een foutmelding heet het type ervan NoneType.
  • indentatie (indentation): de witruimte vooraan een regel, waarmee Python bepaalt wat bij elkaar hoort.
  • blok (block): alle regels die even ver geïndenteerd staan en samen één geheel vormen.
  • commentaar (comment): alles achter een #, dat Python overslaat.

8 Oefeningen

De functies die hierboven op deze pagina gemaakt zijn, staan hier nog klaar en hoef je niet opnieuw te schrijven. Wat je zelf in een oefening schrijft, blijft eveneens bestaan voor de oefeningen erna, zolang je de pagina niet herlaadt.

  1. Voorspel wat Python doet, en probeer het daarna uit in de cel eronder.

    1. Op je rekentoestel mag je het maalteken weglaten en 2(3 + 4) schrijven. Wat doet Python met die regel?
    2. Op je rekentoestel schrijf je een macht met ^. Wat verwacht je bij 2 ^ 3, en wat krijg je?
    3. Je hebt 100 potloden en je stopt ze in dozen van 12. Welke uitdrukking geeft het aantal volle dozen, en welke het aantal potloden dat overblijft? En wat geeft 100 / 12?

    a. TypeError: 'int' object is not callable. Python leest 2(3 + 4) als een aanroep van 2, net zoals f(3 + 4) een aanroep van f is. Het maalteken is verplicht, dus 2 * (3 + 4).

    b. 1, en geen foutmelding. Een macht schrijf je 2 ** 3, en dat geeft 8. Het teken ^ bestaat wel degelijk in Python en staat voor XOR, een bewerking op bits die niet bij deze les hoort. Ze staat hier enkel om te verklaren waarom Python geen foutmelding geeft. Geen foutmelding betekent dus niet dat er staat wat je bedoelde.

    c. 100 // 12 geeft 8 volle dozen en 100 % 12 geeft 4 potloden die overblijven. 100 / 12 geeft 8.333333333333334, want / levert altijd een kommagetal, ook bij 12 / 4, dat 3.0 geeft en niet 3.

  2. Vul de functie hieronder aan.

    Tel de twee getallen op en deel door 2. Let op de haakjes, want a + b / 2 deelt alleen b.

  3. Schrijf schuine_zijde(a, b), die de lengte van de schuine zijde van een rechthoekige driehoek teruggeeft. Gebruik in plaats van een vierkantswortel voorlopig een rationale exponent. \(\sqrt{n}\) wordt n ** 0.5. Zet er een commentaar bij die uitlegt wat ** 0.5 doet, want een lezer die dat niet weet, ziet enkel een macht staan.

    De stelling van Pythagoras geeft je het kwadraat van de schuine zijde. kwadraat staat van hierboven nog klaar, dus blijft enkel de wortel over.

    Een commentaar zou kunnen zijn:

    De bedoeling is dat ze iets toevoegt. # bereken de schuine zijde herhaalt enkel de naam van de functie. Bij ** 0.5 valt er wel iets uit te leggen: ** aanvaardt ook niet-gehele exponenten, en omdat \(n^{1/2} = \sqrt{n}\) levert n ** 0.5 dus de vierkantswortel.

  4. Is het mogelijk gemiddelde3(a, b, c) te schrijven door gemiddelde twee keer te gebruiken? Heb je oefening 2 uitgevoerd, dan staat gemiddelde nog klaar. Controleer je functie met 0, 0 en 6.

    Reken eerst zelf uit wat het gemiddelde van 0, 0 en 6 is. Laat Python daarna gemiddelde(gemiddelde(0, 0), 6) uitrekenen, en vergelijk de twee.

    Hergebruik werkt niet. gemiddelde(gemiddelde(a, b), c) geeft 3.0 bij 0, 0 en 6, terwijl het gemiddelde 2.0 is: a en b wegen dan elk een kwart en c de helft.

  5. Accepteert Python deze namen? Antwoord telkens met ja of nee, en zeg bij een nee wat er misloopt.

    1. aantal_leerlingen
    2. 2de_poging
    3. lengte2
    4. gemiddelde-score
    5. return
    6. AantalLeerlingen

    a. Ja, en het is meteen de gewoonte: kleine letters met liggende streepjes ertussen.

    b. Nee. Een naam mag niet met een cijfer beginnen. Python begint 2de te lezen als een getal en meldt invalid decimal literal.

    c. Ja. Een cijfer mag wel, zolang het niet vooraan staat.

    d. Nee. Een streepje is geen letter, cijfer of liggend streepje. Vervelender is wat Python er wel van maakt: het leest gemiddelde-score als de aftrekking gemiddelde - score. Bestaan die twee namen, dan krijg je geen foutmelding maar gewoon een ander antwoord dan je bedoelde.

    e. Nee. return is voorbehouden aan de taal zelf.

    f. Ja, dit mag. Het is alleen niet de gewoonte in Python, waar je aantal_leerlingen schrijft. Een regel van de taal en een gewoonte onder programmeurs zijn twee verschillende dingen.

  6. Hierboven op deze pagina staat kwadraat nog klaar. Voorspel wat de cel hieronder doet, en voer ze daarna uit.

    NameError: name 'Kwadraat' is not defined. Kwadraat en kwadraat zijn voor Python twee verschillende namen. Een hoofdletter is dus geen opmaak maar een deel van de naam.

  1. Schrijf middelste(a, b, c), die van drie getallen het middelste teruggeeft, dus dat wat niet het grootste en niet het kleinste is. Bij 3, 9 en 5 is dat 5.

    1. Gebruik alleen min, max, + en -.

      Gebruik de som van de getallen, min(a, b, c) en max(a, b, c).

      Van de drie getallen ken je het grootste en het kleinste al. Trek je die twee van de som af, dan blijft het middelste over. Dat klopt ook wanneer er twee even groot zijn.

    2. Gebruik nu alleen min en max, dus zonder optellen of aftrekken.

      Uit a, b en c kan je drie paren vormen. Neem van elk paar het grootste, en vergelijk de drie uitkomsten met elkaar.

      We weten de verhoudingen niet tussen de getallen, maar elk getal zit in twee paren. Twee tussenresultaten van max zijn bijgevolg beide het grootste getal. Het derde paar bestaat uit de twee kleinste en levert met max dus het middelste getal als tussenresultaat. Als we van de drie tussenresultaten dan het min nemen, bekomen we altijd het middelste getal. Met min en max van plaats gewisseld werkt het net zo goed: max(min(a, b), min(b, c), min(a, c)). Er zijn ook nog andere oplossingen mogelijk.