Hoofdstuk 8 - Eigen Functies

Let op: log eerst in bij repl.it
Meteen naar de Afsluitende Opgaven
Terug naar de cursus pagina

In de les over Bestaande Functies hebben we geleerd hoe je eenvoudige functies kunt gebruiken, zoals max() en str(), en hoe je functies kunt importeren uit modules zoals random. Dit hoofdstuk beschrijft hoe je je eigen functies kan maken.


Het nut van functies

Waarom zou je functies willen maken?

Functies maken

Iedere functie heeft een naam, nul of meer parameters, en mogelijk een retourwaarde. Als je je eigen functies maakt, moet je al deze elementen declareren. Dat ziet er zo uit:

def functieNaam ( parameter_naam ):
    actie()

Functienamen moeten voldoen aan dezelfde eisen als variabele namen, dus, alleen letters, cijfers, en underscores, en ze mogen niet beginnen met een cijfer. Om onderscheid te maken is het goed om functienamen in camelCase te schrijven (dus aan elkaar plakken en elk woord steeds met een hoofdletter beginnen), en bij variabelen een underscore ('_') te gebruiken zoals variabel_naam. Functienamen moeten beschrijvend zijn. Een functie die test of iets een bepaalde eigenschap heeft en daarom True of False retourneert geef je een naam als is...(), bijvoorbeeld isEven. We zetten functie definities altijd bovenaan de code.

Een functie kan nul of meer parameters (of variabelen) hebben. Meerdere parameters worden gescheiden door een komma. Het blok code dat bij een functie definitie hoort moet inspringen ( in dit voorbeeld: actie() ).

Hoe Python omgaat met functies

We bekijken eerst hoe Python met functies omgaat.

Bekijk het onderstaand programma. De code is opgebouwd uit twee delen:

  1. Functie definities: Dit programma definieert één functie, die totZiens() heet. Deze functie heeft geen parameters. De twee regels dat ingesprongen zijn horen bij de functie. Dit is alleen een beschrijving van een functie. Het wordt nog niet uitgevoerd, dat gebeurt pas als totZiens() in het hoofdprogramma aangeroepen wordt.
  2. Hoofdprogramma: Deze regels code worden een-voor-een uitgevoerd. Functie definities horen niet bij het hoofdprogramma.

Bij het uitvoeren van het programma worden de functie definities overgeslagen: er wordt meteen naar het hoofdprogramma gesprongen. Daar wordt als eerste "Hallo!" geprint (regel 7). Daarna wordt de functie totZiens() aangeroepen (regel 8). Het programma springt naar de definitie van totZiens() (regel 2). Deze print de tekst "..en dan.. " (regel 3) en daarna "tot ziens!"(regel 4). Dan is de functie afgelopen (er wordt namelijk niet meer ingesprongen). Na afloop van de functie keert het terug naar het hoofdprogramma, waar hij verder gaat met de volgende regel code: het print "Klaar!"(regel 9). Het programma is dan klaar en stopt. Python voert de code van een functie dus alleen uit als de functie wordt aangeroepen.

Zie het volgende filmpje voor extra uitleg over functies:

Opgave 8.2.1A Een functie aanroepen

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Opgave 8.2.1B Een eigen functie maken: TekenSnoep

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Overzichtelijke hoofdprogramma

Het grote voordeel van gebruik maken van functies is dat het hoofdprogramma nu duidelijk samenvat wat de code als geheel doet. Dat zie je in de code van je vorige opdracht ook: in het hoofdprogramma wordt de pen neergezet, snoep getekend en daarna het stokje:

#HOOFDPROGRAMMA
turtle.pendown()
tekenSnoep()
tekenStok()
turtle.done()

Verschillende soorten functies: met en zonder parameters en retourwaarden

Een functie bij het programmeren is net als een functie die iemand heeft in een bedrijf: ze moeten iets doen. Soms moet die persoon informatie van je hebben om zijn werk goed te doen (invoer). Soms levert het een concreet product op (iemand maakt iets voor je), en soms een dienst op (iemand doet iets voor je). Neem de bakker bijvoorbeeld:

Je hebt verschillende soorten functies:
  1. Geef je geen informatie aan (dus zonder parameters), en geeft niets terug (dus levert geen retourwaarde op): Soms kan iemand iets doen zonder dat hij of zij daar specifiek informatie voor nodig heeft, en zonder dat het echt een tastbare retourwaarde (of resultaat) oplevert. Bijvoorbeeld de buschauffeuse: ze rijdt rondjes en stopt op vaste locaties, je stapt in de bus, je hoeft haar niet te vertellen waar ze heen (geen parameters) moet rijden en ze geeft jou ook niets (levert geen concreet resultaat op).
  2. Geef je wel informatie aan (dus met parameters), maar geeft niets terug (dus levert geen retourwaarde op): Soms heeft iemand specifiek informatie om iets te doen, maar het hoeft niet per se een tastbare retourwaarde (of resultaat) op te leveren. Bijvoorbeeld de bibliothecaresse die boeken inneemt, je geeft haar jouw boeken, zei registreert dat je ze in hebt geleverd en zet op de juiste plek terug in de bibliotheek.
  3. Geef je wel informatie aan (dus met parameters), en geeft je iets terug (dus levert met return een concrete retourwaarde op): Soms heeft iemand specifiek informatie om iets te doen, en geeft je ook iets terug (een resultaat) waar je daarna iets mee kan doen. Bijvoorbeeld de loketmedewerker bij een geldwisselkantoor: je geeft haar Euro’s omdat je Dollars nodig hebt voor je vakantie in Amerika, ze berekent hoeveel Dollars die Euro’s waard zijn, en geeft je Dollars terug.
  4. Geef je geen informatie aan (dus zonder parameters), maar geeft je wel iets terug (dus levert met return een concrete retourwaarde): Soms heeft iemand geen specifiek informatie nodig om iets te doen, maar geeft je wel iets terug (een resultaat) waar je daarna iets mee kan doen. Bijvoorbeeld een verkeersregelaar, die geeft aanwijzingen wat je moet doen.
We bekijken nu voorbeelden van functies met en zonder parameters en retourwaarden.

I. Functies zonder parameters, zonder retourwaarde

Soms gebruik je functies zonder parameters (zonder dat je het specifieke informatie hoeft te geven) en zonder dat het een retourwaarde (of resultaat) teruggeeft. Dan gebruik je een functie om je code te structureren en op te ruimen. Heb je code dat bij elkaar hoort of code dat je vaker gebruikt? Daar kun je dan een functie van maken.

Hieronder zie je een voorbeeld van een functie waarbij de regels code voor het tekenen van een driehoek bij elkaar staan in een functie:

Opgave 8b.1 Figuurtje tekenen

Klik hier voor een uitwerking.

II. Functies met parameters, zonder retourwaarde

Soms geef je specifieke informatie aan een functie mee (parameter) zodat het precies doet wat jij in die situatie wil. We bekijken nu een voorbeeld zonder dat de functie een retourwaarde (of resultaat) teruggeeft.

Heb je code dat je vaker gebruikt, maar er telkens iets anders uit ziet? Daar kun je dan een functie van maken. In het programma hieronder wordt een kunstwerk gemaakt. Je ziet een functie tekenCirkel( kleur ) die als extra informatie (parameter) meekrijgt met welke kleur dat moet gebeuren. In het hoofdprogramma wordt bij het tekenen van een cirkel een kleur aangegeven. De waarde zet je tussen de haakjes van de functie aanroep, bijvoorbeeld tekenCirkel( "red" )

De parameters van een functie zijn variabelen die je kunt gebruiken in de functie, en die hun (eerste) waarde krijgen tijdens de functie aanroep. De parameters zijn "lokaal" voor de functie, dat wil zeggen, ze kunnen niet benaderd worden door code die niet in het blok code van de functie staat.

Opgave 8.2.2.1AA Gegroet

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Opgave 8.2.2.1A Teken vierkant met parameters

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Opgave 8.2.2.1B Teken lolly met parameters

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

III. Functies met parameters, met retourwaarde

Voor de meeste berekeningen heb je informatie (parameters) nodig, en lever je ook een retourwaarde (resultaat) op. Het is belangrijk om in het hoofdprogramma de waarde dat geretourneerd wordt in een variabele op te slaan. In je programma kun je later met dat variabele verder werken.

In de code hieronder, krijgt de functie plakWoordenAanElkaar twee woorden als parameters binnen en plakt deze aan elkaar. Bij de aanroep van de functie op regel 7, wordt het resultaat opgeslagen in de variabele samenstelling. Deze variabele wordt vervolgens in regel 8 afgedrukt:

Merk op dat:

Een groot voordeel van met functies werken is dat je elk brok los van elkaar kunt bedenken, schrijven en testen. Zo is het makkelijker, als je een fout maakt, erachter te komen waar het zit en te bedenken hoe je het moet oplossen. In de code hierboven kan ik dus, als ik de kosten ga berekenen, me alleen daarmee bezighouden. Met veel print kan ik waarden naar het scherm afdrukken om te controleren of er ook echt gebeurt wat ik verwacht dat er gebeurt: dat heet testen. Als ik een fout vind kan ik diezelfde printjes gebruiken om te achterhalen waar de fout zit: dat heet debuggen.

Opgave 8.2.2.3 Lolly kleur en maat: functie met 2 parameters

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Opgave 8b.4 Iets berekenen

Klik hier voor een uitwerking.

Opgave 8.2.1 Bereken cijfer

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

IV. Functies zonder parameters, met retourwaarde

Een functie kan informatie opleveren, zonder dat het per se informatie nodig heeft. In het geval hieronder is een compliment de retourwaarde. De functie zelf heeft geen informatie nodig, en heeft dus ook geen parameters.

Zie het volgende filmpje voor extra uitleg over functies en parameters:

Opgave 8.2.6 Volume van een balk

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Functies aanroepen vanuit andere functies

Functies mogen andere functies aanroepen, zolang die andere functies maar bekend zijn bij de aanroepende functie. Bijvoorbeeld, hieronder zie je hoe de functie tekenLolly() de functies tekenSnoep() en tekenStok() gebruikt om de lolly als geheel te tekenen.

Opgave 8.2.9 Dorp tekenen: Functies aanroepen vanuit andere functies

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Opgave 8.2.10.1 isEven

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Functie commentaar voor de leesbaarheid

Je kunt je code beter leesbaar maken door goede namen te kiezen voor variabelen en functies, door gebruik te maken van spaties en witregels. Daarnaast kun je met commentaar je code uitleggen. Het idee achter een functie is dat de gebruiker van de functie de code van de functie niet hoeft te kennen. Daarom moet wat de functie doet, en hoe de functie werkt, worden uitgelegd met commentaar. Functie commentaar schrijf je boven de functie definitie.

In commentaar bij een functie moet je drie zaken uitleggen: Voorbeeld:

Een functie hoort geen neveneffecten te hebben. Dat wil zeggen, een functie isEven() bepaalt of een getal even of oneven is, maar doet verder helemaal niks!

Bereik van variabelen

Het bereik van een variabele is het blok code waarin de variabele is gedeclareerd, en alle blokken code die daarbinnen vallen. Bijvoorbeeld:

Figuur: Scope van blokken code
Er bestaan lokale variabelen die binnen een beperkt bereik te gebruiken zijn (bijvoorbeeld een blok code of een functie), en globale variabelen die je door je hele programma kunt gebruiken. We bespreken nu beiden.

Lokale variabelen

Een variabele die je binnen een functie aanmaakt bestaat alleen binnen die functie. Zo'n variabele heet een "lokale variabele". Zodra de functie eindigt, worden de lokale variabelen van de functie vernietigd. Ze staan niet langer in het geheugen van de computer. Zo'n lokale variabele is dus compleet onafhankelijk van het hoofdprogramma. Wil je de waarde in het hoofdprogramma gebruiken, dan moet je het retourneren, anders heeft het geen effect op het hoofdprogramma.

In het voorbeeld hieronder zie je de lokale variabele verdubbelde_punten die wordt gedeclareerd op regel 3 en na regel 4 ophoud met bestaan omdat de functie dan ophoudt (dat zie je omdat het inspringen dan ook ophoudt). Om de verdubbelde waarde later nog in het hoofdprogramma nog te kunnen printen (regel 8) moet eerst de waarde dat de functie teruggeeft opgeslagen worden in een variabele (regel 7).

Opgave 8.3.1.2 Levensduur van variabelen

Klik hier voor een uitleg.

Globale variabelen

"Globale variabelen" definieer je bovenaan je programma en zijn zichtbaar in alle functies van een programma. Het verschil met lokale variabelen is dat die alleen zichtbaar zijn binnen de functie of blok code waarin ze gedeclareerd worden.

Het is een goede gewoonte om zo min mogelijk globale variabelen te gebruiken, omdat het onoverzichtelijk wordt wat er allemaal mee gebeurt. Als je een bepaalde waarde binnen meerdere functies wilt gebruiken kun je dat met parameters en retourwaardes doen. In het voorbeeld hieronder zie je hoe de prijs (zonder BTW) als parameter aan de functie wordt gegeven, en de prijs inclusief BTW wordt geretourneerd.

De enige globale variabelen die je echt wel wilt gebruiken zijn constanten. Constanten zijn waarden die gedurende het programma niet veranderen. Voor de naam van een constante gebruik je hoofdletters en maak je deze boven aan je programma aan, bijvoorbeeld: AANTAL_UREN_PER_DAG = 24, of zoals in het volgende voorbeeld PERC_BTW.

Opgave 8.3.2 Constanten

Speel met een vriend of vriendin een paar keer steen-papier-schaar. Houd op een blaadje bij hoe vaak ieder gewonnen heeft en hoe vaak er gelijk is gespeeld.

Bekijk je scoreblad en bepaal wat de constanten en wat de variabelen zijn.

Klik hier voor een uitleg.

Soms moet je echt globale variabelen gebruiken omdat het niet anders kan. Om een globale variabele binnen een functie aan te kunnen passen moet je deze eerst met global variabel_naam binnen de functie benoemen. Bekijk het voorbeeld:

Opgave 8.3.1.3 Waarde van een lokale variabele delen met een return

Klik hier om je eigen oplossing te vergelijken met een model oplossing.


Optioneel: Extra theorie

Hieronder volgt extra theorie voor wie het interessant vindt. Deze theorie wordt niet getoetst, maar het toepassen van de kennis wordt wel in je PO gewaardeerd met een hoger cijfer :)

Optioneel: Afvangen van ongeldige invoer

Stel je nu voor dat je deze berekening alleen wilt uitvoeren met positieve getallen (wat niet gek zou zijn, aangezien een driehoek alleen zijden van groter dan 0 kan hebben).

Je kunt dit in de code van je functie afvangen door te controleren of het positieve getallen zijn en anders een foutmelding te geven.

Het hoofdprogramma verwacht dat de functie pythagoras() een getal teruggeeft dat afgedrukt kan worden. Dus ook als de invoer niet goed is, zal pythagoras() iets moeten opleveren. Je moet er altijd heel duidelijk over zijn wat je functie retourneert, en ervoor zorgen dat een retourwaarde ook altijd opgeleverd wordt, ongeacht de omstandigheden.

Vaak is het handig om -1 te retourneren bij ongeldige invoer. Je moet er natuurlijk wel voor dat je dan een foutmelding geeft. Ook is het belangrijk om dit soort informatie in commentaar bij je functie te zetten. Als je (of iemand anders) die functie ooit ergens anders voor gebruikt dan weet je dat je daar een foutmelding voor moet schrijven.

Het volgende voorbeeld vangt ongeldige invoer af:

Optioneel: Opgave 8.4 Volume van een balk met foutafhandeling

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Optioneel: Meerdere retourwaardes

In Python ben je niet beperkt in je functies tot slechts één retourwaarde. Je kunt meerdere waardes in één keer retourneren door er komma’s tussen te zetten. Als je deze waardes wilt gebruiken in je programma na aanroep van de functies, moet je ze toekennen aan meerdere variabelen. Die zet je allemaal aan de linkerkant van de toekenning-operator, ook met komma’s ertussen. Dit kan ik het beste illustreren aan de hand van een voorbeeld:

De functie plusDagen() krijgt vier argumenten, namelijk integers die een jaar, een maand, een dag, en een aantal dagen die je wilt optellen bij de datum die wordt weergegeven door de eerste drie argumenten. Er worden drie waardes geretourneerd, namelijk een nieuw jaar, een nieuwe maand, en een nieuwe dag. De code stopt die in de variabelen y, m, en d.

Als je de code hierboven bekijkt, vraag je je misschien af hoe plusDagen() precies werkt. Zoals ik al zei, het is een voordeel van functies dat zolang ze hun werk doen en je weet wat de argumenten zijn en wat er geretourneerd wordt, dat je niet hoeft te weten hoe de functie in elkaar zit. Je kunt de functie gebruiken zonder kennis van het interne proces. Dus je mag gewoon negeren wat je in plusDagen() ziet staan.

Optioneel: Opgave 8.5 Oplosser voor kwadratische vergelijkingen

Deze opdracht wordt nog niet automatisch gecontroleerd. Klik hier om je eigen oplossing te vergelijken met een model oplossing.

Optioneel: Modules

Het maken van een module is eenvoudig. Je maakt gewoon een Python bestand, met de extensie .py, en plaatst er de functies in die je in de module wilt hebben. Je kunt dit Python bestand dan importeren in een ander Python programma (je gebruikt gewoon de naam van het bestand zonder de extensie .py; het bestand moet in dezelfde folder als het programma staan, of in de folder waar Python altijd zoekt naar modules), en je kunt de functies gebruiken op dezelfde manier als je functies uit de reguliere Python modules gebruikt, dat wil zeggen, je kunt ofwel specifieke functies uit de module importeren, ofwel de hele module importeren en de functies gebruiken via de <module>.<functie>() syntax.

main()

Als je de code van andermans Python programma’s bekijkt, zeker programma’s die functies bevatten die je mogelijk zou willen importeren, zie je vaak een constructie als de volgende:

 def main():
    # code...

if __name__ == '__main__':
    main()

De functie main() bevat feitelijk het hoofdprogramma, dat andere functies kan aanroepen.

Je hoeft dit niet precies te begrijpen, maar wat hier aan de hand is, is het volgende: het Python bestand bevat code die als programma kan draaien, of de functies die het bevat kunnen geïmporteerd worden in andere programma’s. De bovenstaande constructie zorgt er voor dat de code in main()(dus het hoofdprogramma) alleen wordt uitgevoerd als het programma als een separaat programma is gestart, en niet als een module in een ander programma geladen is. Als in plaats daarvan het programma als module is geladen, kunnen alleen de functies in het programma worden geïmporteerd, en wordt de code voor main() genegeerd.

Een Python bestand dat een dergelijke constructie bevat en dat voornamelijk als module wordt gebruikt, heeft vaak code in main() die de functies test. Dat kan nuttig zijn tijdens de ontwikkeling van de module.

Deze constructie heeft echter nog een tweede toepassing. Omdat main() een functie is, hoef je als je het programma tussentijds wilt verlaten, niet de exit() functie uit de sys module te gebruiken. In plaats daarvan kun je gewoon return doen in de main() functie. Dit vermijdt de lelijke fout-boodschap die sommige editors geven bij gebruik van exit().

Optioneel Opgave 8.6 Module binomiaalcoëfficiënt


Wat je geleerd hebt over Eigen Functies

In dit hoofdstuk is het volgende besproken:


Verder naar de Afsluitende Opgaven over Eigen Functies
Terug naar de cursus pagina