Hoofdstuk 8 - Eigen Functies
Let op: log eerst in bij repl.itMeteen 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?
- Decompositie: Een (complexe) probleem opdelen in kleinere stukken om het makkelijker op te lossen. Ieder stuk ontwikkel en test je los van de rest op. De code kun je dan later gebruiken zonder er verder over na te denken.
- Hergebruik: Met functies kun je een bepaalde stuk code op meerdere plekken in je programma gebruiken. Je kunt dan beter verwijzen naar waar de code staat (de functie) dan het te kopiëren. Ook kun je dan code aan andere programmeurs beschikbaar stellen (via modules).
- Abstractie: Met parameters kun je de code voor meerdere toepassingen gebruiken, en wordt het ook makkelijker te lezen en te onderhouden.
- Overzichtelijkheid: Met functies kun je lange code opsplitsen en daardoor overzichtelijker 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:
- 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 alstotZiens()in het hoofdprogramma aangeroepen wordt. - 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:
- Wat doet de bakker? Hij bakt brood.
- Welk informatie heeft de bakker van je nodig? Hij moet weten welk brood je wilt, en bijvoorbeeld of je een hele of een half brood wil. Dit informatie geef je aan de bakker.
- Wat geeft de bakker jou? De bakker levert een brood op dat hij aan jou geeft.
- 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).
- 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.
- Geef je wel informatie aan (dus met parameters), en geeft je iets terug (dus levert met
returneen 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. - Geef je geen informatie aan (dus zonder parameters), maar geeft je wel iets terug (dus levert met
returneen 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.
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:
- De variabele
resultaataangemaakt wordt binnen de functie, en daardoor alleen binnen de functie bestaat. Dit heet een lokale variabele. resultaatwordt aangemaakt op regelnummer 3, en bestaat niet meer na regel 4.- Wil je de waarde van variabele
resultaatna de functie nog gebruiken, dan moet je deze met eenreturnopleveren aan het hoofdprogramma. - De waarde van
resultaatwordt in dit voorbeeld op regel 7 teruggegeven aan het hoofdprogramma en wordt opgeslagen in de variabelesamenstelling.
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:- Wat de functie doet
- Onder welke omstandigheden de functie (niet) goed werkt
- Welke parameters meegegeven moeten worden
- Wat de functie retourneert, ook bij ongeldige invoer
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:

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:
- Het nut van functies
- Functies maken
- Waarden aan een functie meegeven als parameters
- Waarden uit functies retourneren middels
return - Het verschil in bereik en levensduur tussen lokale en globale variabelen
- Juiste en zinvolle naamgeving aan functies
- Dat constanten gebruikt worden voor variabelen die tijdens een programma niet veranderen, en met hoofdletters geschreven worden
- Gebruik van commentaar in functies
- Code overzichtelijk te houden door in je code deze volgorde aan te houden: globale variabelen, functie definities, hoofdprogramma
Verder naar de Afsluitende Opgaven over Eigen Functies
Terug naar de cursus pagina