Hoofdstuk 8 - Functies
01 - Functies Definiëren
- Functies zijn blokken code met een naam, die zijn ontworpen om één specifieke taak uit te voeren
- Als je de code van een functie wilt gebruiken moet je de functie 'aanroepen'
- Met het gebruik van functies zijn je programma's makkelijker te schrijven, lezen, testen en repareren
- Het keyword
defgeeft aan dat je een functie aan het definiëren bent
# De functie
def greeting():
print("Goedemorgen Kuala Lumpur!")
# Het aanroepen
greeting()
Goedemorgen Kuala Lumpur!
- Na de functienaam komt altijd een set haakjes voor de parámeters (uitspraak !)
- Parameters zijn variabelen die in de functie kunnen worden gebruikt
- Parameters opgeven is niet verplicht maar het plaatsen van een set haakjes wel
def greeting(country):
print("Hallo, " + country.title() + "!")
greeting('Maleisië')
Hallo, Maleisië!
- Alle ingesprongen regels direct onder
defnoemen we de functie-body - In de functie-body staat de werkelijke code van de functie
- Bij het aanroepen van een functie moet de verwachte data worden meegestuurd; we noemen deze data 'argumenten'
def greeting(country):
print("Hallo, " + country.title() + "!")
greeting()
TypeError: greeting() missing 1 required positional argument: 'country'
Samengevat:
- Bij het declareren van een functie zijn haakjes achter de functienaam verplicht
- Tussen deze haakjes kun je parameters plaatsen (dit zijn “lege” variabelen die binnen de functie gebruikt kunnen worden)
- Een functie kan pas worden aangeroepen nadat deze is gedeclareerd
- Bij het aanroepen van een functie kun je argumenten meesturen (dit zijn de daadwerkelijke waarden die in de parameters terechtkomen)
- Parameters = plaatshouders in de functiedefinitie
- Argumenten = de data die je meestuurt bij het aanroepen van de functie
- In de praktijk worden de termen parameters en argumenten soms door elkaar gebruikt
02 - Argumenten doorgeven
- Soms moet je meerdere argumenten meegeven bij het aanroepen van een functie
- Positional arguments: de volgorde van de argumenten moet gelijk zijn aan de volgorde van de parameters in de functiedefinitie
- Keyword arguments: je koppelt waarden aan parameters met
naam=waarde, waarbij de volgorde niet meer uitmaakt - Default arguments: in de functiedefinitie is een standaardwaarde voor een parameter opgegeven, zodat je dit argument mag overslaan bij het aanroepen
Positional arguments
- Positional arguments hebben een vaste volgorde
- De volgorde van de parameters in de functie moet exact overeenkomen met de volgorde van de argumenten bij het aanroepen van de functie
def country_fact(country, fact):
print("\nLand: " + country)
print("Opmerkelijk feit: " + fact)
print("Welk land wil je meer over weten?")
country_fact("Madagaskar", "90% van alle planten en dieren\nkomt nergens anders ter wereld voor.")
Welk land wil je meer over weten?
Land: Madagaskar
Opmerkelijk feit: 90% van alle planten en dieren
komt nergens anders ter wereld voor.
- Als je de functie
country_factaanroept, moet je de argumentencountryenfactopgeven in die volgorde - Je kunt een functie zo vaak aanroepen als je wilt – dat maakt functies zo efficiënt en herbruikbaar
- Je kunt in je functie zoveel positionele parameters gebruiken als nodig is (zoals
countryenfact)
def country_fact(country, fact, continent):
print("\nLand: " + country)
print("Weetje: " + fact)
print("Werelddeel: " + continent)
print("Gekke en zeldzame weetjes over landen:")
country_fact(
"Mongolië",
"Mongolië heeft meer paarden dan mensen in sommige regio’s.",
"Azië"
)
country_fact(
"Japan",
"Japan heeft een eiland waar alleen tamme konijnen wonen (Ōkunoshima).",
"Azië"
)
country_fact(
"Canada",
"Canada heeft het langste kustlijn ter wereld — langer dan die van alle andere landen samen.",
"Noord-Amerika"
)
Gekke en zeldzame weetjes over landen:
Land: Mongolië
Weetje: Mongolië heeft meer paarden dan mensen in sommige regio’s.
Werelddeel: Azië
Land: Japan
Weetje: Japan heeft een eiland waar alleen tamme konijnen wonen (Ōkunoshima).
Werelddeel: Azië
Land: Canada
Weetje: Canada heeft het langste kustlijn ter wereld — langer dan die van alle andere landen samen.
Werelddeel: Noord-Amerika
Keyword arguments
- Een keyword argument is een naam-waarde-paar dat je aan een functie meegeeft
- Je geeft de naam van de parameter en de bijbehorende waarde op bij het aanroepen van een functie
- Bij het gebruik van keyword arguments is de volgorde van de argumenten niet belangrijk
- Keyword arguments verduidelijken de waarde in de functieaanroep en maken de code beter leesbaar
def surface(country, km2):
print("\nLand: " + country)
print(str(km2) + "\t miljoen km²")
print(str(round(0.3861 * km2, 2)) + "\t miljoen sq mi")
print("Welk land is groter: Groenland of China?")
surface(country="Groenland", km2=2.1)
surface(km2=9.5, country="China")
Welk land is groter: Groenland of China?
Land: Groenland
2.1 miljoen km²
0.81 miljoen sq mi
Land: China
9.5 miljoen km²
3.67 miljoen sq mi
Default arguments
- Als je een functie schrijft kun je voor een parameter een standaardwaarde opgeven
- Geef je bij de functieaanroep wél een argument mee voor de parameter, dan wordt dat argument gebruikt
- Geef je bij de functieaanroep géén argument mee, dan wordt de standaardwaarde gebruikt
def map_projection(year, projection="mercator"):
if projection == "mercator":
print(str(year) + ": De Mercatorprojectie vertekent oppervlaktes")
print("Google Maps - hoekgetrouw")
else:
print(str(year) + ": De Gall-Petersprojectie vertekent loodrechte lijnen")
print("Google Earth - oppervlaktegetrouw")
print("Hoe verschillend projecties de wereld tonen:")
map_projection(1569)
map_projection(1973, "gall-peters")
Hoe verschillend projecties de wereld tonen:
1569: De Mercatorprojectie vertekent oppervlaktes
Google Maps - hoekgetrouw
1973: De Gall-Petersprojectie vertekent loodrechte lijnen
Google Earth - oppervlaktegetrouw
03 - Retourwaarden
- In plaats van een resultaat te printen kan een functie ook een waarde returnen
- De retourwaarde(n) van een functie worden teruggestuurd naar de regel die de functie heeft aangeroepen
def citizen(activity):
match activity:
case "werken":
return "Loonbelasting"
case "verdienen":
return "Inkomstenbelasting"
case "wonen":
return "WOZ-belasting"
case "uitgeven":
return "BTW"
case "sparen":
return "Vermogensbelasting"
case "investeren":
return "Dividendbelasting"
case "ondernemen":
return "Omzetbelasting"
case "rijden":
return "Motorrijtuigenbelasting"
case "tanken":
return "Accijns"
case "weggeven":
return "Schenkbelasting"
case "overlijden":
return "Erfbelasting"
case "hond":
return "Hondenbelasting"
case "afval":
return "Afvalstoffenheffing"
case "riool":
return "Rioolheffing"
case "waterzuivering":
return "Zuiveringsheffing"
case "energie gebruiken":
return "Energiebelasting"
case "overnachten":
return "Toeristenbelasting"
case "parkeren":
return "Parkeerbelasting"
case "reclame maken":
return "Reclamebelasting"
case "grond gebruiken":
return "Precariobelasting"
output = citizen("overlijden")
print(output)
Erfbelasting
Het bovenstaande voorbeeld werd onbedoeld steeds uitgebreider.
Het oorspronkelijke if-statement is vervangen door een case ;)
- Wanneer je een functie aanroept die een waarde retourneert, moet je een variabele gebruiken om deze retourwaarde op te slaan
- Een functie kan optionele argumenten bevatten; deze hebben een standaardwaarde die wordt gebruikt als je zelf geen argument meegeeft
def get_net_income(first_name, last_name, profession='', total_tax_rate=0.75):
"""
Deze functie berekent de real-life belastingdruk van 1 euro brutoloon.
"""
if profession:
full_name = first_name + ' ' + profession + ' ' + last_name
else:
full_name = first_name + ' ' + last_name
net = 1 - total_tax_rate
net = round(net, 2)
return full_name.title() + " houdt netto €" + str(net) + " per euro over."
# Voorbeelden
worker = get_net_income("jan", "de vries", "vuilnisman", total_tax_rate=0.65)
print(worker)
doctor = get_net_income("anne", "brouwer", "huisarts", total_tax_rate=0.80)
print(doctor)
Jan Vuilnisman De Vries houdt netto €0.35 per euro over.
Anne Huisarts Brouwer houdt netto €0.2 per euro over.
Een woordenboek retourneren
- Een functie kan ook ingewikkeldere datastructuren retourneren zoals een lijst of woordenboek
def build_country(name, region, tax_rate=''):
country = {'name': name, 'region': region}
if tax_rate:
country['tax_rate'] = tax_rate # belastingdruk in procenten
return country
country1 = build_country('Monaco', 'Europa')
print(country1)
country2 = build_country('Qatar', 'Midden-Oosten', tax_rate=0)
print(country2)
country3 = build_country("Bahama's", 'Caribisch gebied', tax_rate=0)
print(country3)
country4 = build_country('Brunei', 'Azië', tax_rate=0)
print(country4)
{'name': 'Monaco', 'region': 'Europa'}
{'name': 'Qatar', 'region': 'Midden-Oosten', 'tax_rate': 0}
{'name': "Bahama's", 'region': 'Caribisch gebied', 'tax_rate': 0}
{'name': 'Brunei', 'region': 'Azië', 'tax_rate': 0}
Een functie met een while-loop
def favorite_country(country, continent):
full = country + " (" + continent + ")"
return full.title()
while True:
land = input("\nNaar welk land wilt u op vakantie? (typ 'q' om te stoppen)\nLand: ")
if land.lower() == 'q':
break
werelddeel = input("Werelddeel: ")
if werelddeel.lower() == 'q':
break
bestemming = favorite_country(land, werelddeel)
print("\nLeuke keuze! " + bestemming + " klinkt prachtig")
Leuke keuze! Cayman Islands (Noord-Amerika) klinkt prachtig
Leuke keuze! Bermuda (Noord-Amerika) klinkt prachtig
Leuke keuze! Luxemburg (Europa) klinkt prachtig
En wat als je naam nu q is?
04 - Een lijst aan een functie geven
- Het is vaak handig om een lijst aan een functie door te geven
# Het is vaak handig om een lijst aan een functie door te geven
def show_facts(facts):
for fact in facts:
msg = "Wist je dat: " + fact + "?"
print(msg)
geography_facts = [
"IJsland geen enkele inheemse mierensoort heeft",
"Australië breder is dan de maan (4000 km vs 3474 km)"
]
show_facts(geography_facts)
Wist je dat: IJsland geen enkele inheemse mierensoort heeft?
Wist je dat: Australië breder is dan de maan (4000 km vs 3474 km)?
Een lijst in een functie aanpassen
- Wanneer je een lijst aan een functie doorgeeft, kan de functie deze lijst aanpassen
- Alle wijzigingen die in de body van de functie worden gedaan, zijn permanent
- De onderstaande twee voorbeelden hebben hetzelfde resultaat, maar:
- het eerste voorbeeld gebruikt géén functies;
- het tweede voorbeeld gebruikt wél functies
- In beide voorbeelden is er een lijst met interessante landen
- Wanneer de landen bezocht zijn, worden ze uit de oorspronkelijke lijst gehaald en in een andere lijst geplaatst
# Voorbeeld 1 – zonder functies
unvisited_countries = [
'Paraguay',
'Mauritius',
'IJsland'
]
visited_countries = []
while unvisited_countries:
current_country = unvisited_countries.pop()
print("Bezoek het land: " + current_country)
visited_countries.append(current_country)
print("\nDe volgende landen zijn bezocht:")
for country in visited_countries:
print(country)
Bezoek het land: IJsland
Bezoek het land: Mauritius
Bezoek het land: Paraguay
De volgende landen zijn bezocht:
IJsland
Mauritius
Paraguay
# Voorbeeld 2 – met functies
def visit_countries(unvisited_countries, visited_countries):
while unvisited_countries:
current_country = unvisited_countries.pop()
print("Bezoek het land: " + current_country)
visited_countries.append(current_country)
def show_visited_countries(visited_countries):
print("\nDe volgende landen zijn bezocht:")
for country in visited_countries:
print(country)
unvisited_countries = ['Paraguay',
'Mauritius',
'IJsland']
visited_countries = []
visit_countries(unvisited_countries, visited_countries)
show_visited_countries(visited_countries)
Bezoek het land: IJsland
Bezoek het land: Mauritius
Bezoek het land: Paraguay
De volgende landen zijn bezocht:
IJsland
Mauritius
Paraguay
- In het tweede voorbeeld is de code die het meeste werk doet verplaatst naar twee functies
- Hierdoor wordt de resterende code overzichtelijker en makkelijker te begrijpen
- Het tweede voorbeeld is makkelijker te onderhouden en uit te breiden
- Uitbreiding: Als je later meer landen wilt bezoeken, roep je de functie eenvoudig opnieuw aan
- Onderhoud: Pas je de functie aan, dan geldt deze wijziging meteen voor alle functieaanroepen
- Het tweede voorbeeld is efficiënter dan dezelfde code op meerdere plaatsen in het programma bij te moeten houden
- Het voorbeeld laat ook goed zien dat elke functie één duidelijke taak moet hebben
- Het is beter om twee losse functies te gebruiken (landen bezoeken & resultaten tonen) dan één functie die beide taken uitvoert
- Wanneer je merkt dat een functie te veel taken uitvoert, splits deze dan op
- Functies kunnen elkaar altijd aanroepen als dat logisch is binnen de structuur van je programma
- Als je niet wilt dat een functie de originele lijst leegt of wijzigt, stuur dan een kopie van de lijst mee
- Wanneer je een lijst rechtstreeks doorgeeft aan een functie, werkt de functie op dezelfde lijst in het geheugen
- Om dat te voorkomen, gebruik je een slice om een kopie te maken:
visit_countries(unvisited_countries[:], visited_countries)– de functie krijgt nu een kopie vanunvisited_countries- De originele lijst blijft hierdoor volledig behouden
05 - Een willekeurig aantal argumenten doorgeven
- Soms weet je vooraf niet hoeveel argumenten een functie moet kunnen verwerken
- In Python kun je een functie schrijven die een willekeurig aantal argumenten accepteert van de regel die de functie aanroept (bijv. met
*args)
def build_route(*cities):
print("Je reisroute bevat de volgende steden:")
print(cities)
build_route('Amsterdam', 'Madrid', 'Asunción')
Je reisroute bevat de volgende steden:
('Amsterdam', 'Madrid', 'Asunción')
- De asterisk bij een parameter geeft Python de opdracht om een lege tuple aan te maken waarin alle extra argumenten worden verzameld
- Een functieaanroep met één of meerdere extra argumenten wordt daardoor op dezelfde manier verwerkt: ze komen allemaal in dezelfde tuple terecht
- In de functie kun je, indien nodig, een
for-loop gebruiken om de items uit de tuple één voor één te verwerken
def build_route(*cities):
print("\nJe reisroute bevat de volgende steden:")
for city in cities:
print("- " + city.title())
build_route('Amsterdam', 'São Paulo', 'Asunción')
build_route('Amsterdam', 'Frankfurt', 'São Paulo', 'Asunción')
Je reisroute bevat de volgende steden:
- Amsterdam
- São Paulo
- Asunción
Je reisroute bevat de volgende steden:
- Amsterdam
- Frankfurt
- São Paulo
- Asunción
Positionele argumenten en een willekeurig aantal extra argumenten
- Een functie kan verschillende soorten argumenten accepteren: positionele argumenten, keyword-argumenten en een willekeurig aantal argumenten
- Een parameter die een willekeurig aantal argumenten accepteert moet altijd als laatste in de functiedefinitie worden gezet
def country_features(country, *facts):
print("\n" + country + " heeft de volgende kenmerken:")
print(facts)
country_features(
"Paraguay",
"90% elektriciteit is hernieuwbaar",
"Goedkoopste land van Zuid-Amerika",
"Jongste bevolkingen ter wereld"
)
country_features(
"IJsland",
"100% verwarming door geothermische energie",
"Geen leger",
"Bijna geen bomen"
)
Paraguay heeft de volgende kenmerken:
('90% elektriciteit is hernieuwbaar', 'Goedkoopste land van Zuid-Amerika', 'Jongste bevolkingen ter wereld')
IJsland heeft de volgende kenmerken:
('100% verwarming door geothermische energie', 'Geen leger', 'Bijna geen bomen')
Positionele argumenten en een willekeurig aantal keyword-argumenten
- Soms wil je een willekeurig aantal argumenten accepteren in je functie
- Maar soms is het niet vooraf duidelijk wat voor soort informatie wordt aangeleverd
- In zo'n geval kan een functie ook een willekeurig aantal sleutel-waarde-paren accepteren die door de aanroepende code worden meegegeven
def build_profile(country, capital, **info):
profile = {}
profile['country'] = country
profile['capital'] = capital
for key, value in info.items():
profile[key] = value
return profile
country_profile = build_profile(
'Zwitserland',
'Bern',
innovation='wereld nr. 1',
safety='schuilkelders voor 100% inwoners',
animals='verboden om één cavia te bezitten'
)
print(country_profile)
{'country': 'Zwitserland', 'capital': 'Bern', 'innovation': 'wereld nr. 1', 'safety': 'schuilkelders voor 100% inwoners', 'animals': 'verboden om één cavia te bezitten'}
- De dubbele asterisk (**) zorgt ervoor dat Python alle meegegeven keyword-argumenten verzamelt in een dictionary, die in de functie beschikbaar is als
info
06 - Functies in modules opslaan
- Functies scheiden blokken code van je hoofdprogramma
- Door beschrijvende namen te gebruiken voor je functies wordt het hoofdprogramma makkelijker te begrijpen
- Je kunt functies opslaan in een apart bestand (een module) om ze vervolgens te importeren
- Een
import-instructie geeft Python de opdracht om de code in de module beschikbaar te maken - Wanneer je functies in een apart bestand opslaat kun je
- details van je programmacode verbergen en je richten op de logica op een hoger niveau
- functies hergebruiken in verschillende programma's
- functies delen met anderen zonder al je code te hoeven delen
- eenvoudig bibliotheken van anderen gebruiken
- Er zijn verschillende manieren om modules te importeren
Een hele module importeren
- Een module is een bestand dat eindigt op .py en de code bevat die je wilt importeren
# bitcoin.py (de module)
def show_price(price):
print(f"De huidige Bitcoin prijs is: {price} euro")
def convert_to_sats(bitcoins):
sats = bitcoins * 100_000_000
print(f"{bitcoins} BTC is gelijk aan {sats} sats")
- Het hoofdprogramma check_bitcoin.py staat in dezelfde map als bitcoin.py
- In dit hoofdprogramma importeren we de hele module
# check_bitcoin.py (het hoofdprogramma)
import bitcoin
bitcoin.show_price(41250)
bitcoin.convert_to_sats(0.0025)
- De import bitcoin regel maakt alle code uit de module beschikbaar in het hoofdprogramma
- Om een functie uit de module te gebruiken, typ je eerst de naam van de module, dan een punt, en dan de naam van de functie
- Dit werkt precies hetzelfde als wanneer de functies rechtstreeks in het hoofdprogramma zouden staan
De huidige Bitcoin prijs is: 41250 euro
0.0025 BTC is gelijk aan 250000 sats
Specifieke functies importeren
- Je kunt ook een specifieke functie uit een module importeren
- Gebruik hiervoor de syntax:
from module_name import function_name - Je kunt meerdere functies tegelijk importeren door de functienamen met een komma te scheiden
- Wanneer je losse functies importeert, hoef je geen puntnotatie (module.func) meer te gebruiken
- Hieronder staat een voorbeeld met een Bitcoin-module
from bitcoin import show_price
show_price(41250)
De huidige Bitcoin prijs is: 41250 euro
Een functie alias
- Bij het importeren van een functie kun je die functie een alias geven
- Een alias gebruik je wanneer een functienaam conflicteert met een bestaande naam in je programma
- Je kunt ook een alias gebruiken om een lange functienaam te verkorten voor het gemak
- Python behandelt de alias als een nieuwe naam voor dezelfde functie
- Hieronder staat een voorbeeld met een Bitcoin-functie die een alias krijgt
from bitcoin import show_price as sp
sp(41250)
sp(39999)
De huidige Bitcoin prijs is: 41250 euro
De huidige Bitcoin prijs is: 39999 euro
Een module alias
- Je kunt ook een alias opgeven voor een hele module
- Met een korte module-alias kun je functies sneller aanroepen
- Het gebruik van module-aliassen kan de leesbaarheid van je code verbeteren
- Hieronder staat een voorbeeld waarin een Bitcoin-module een alias krijgt
import bitcoin as btc
btc.show_price(41250)
btc.convert_to_sats(0.0012)
De huidige Bitcoin prijs is: 41250 euro
0.0012 BTC is gelijk aan 120000 sats
Alle functies van een module importeren
- Python kan alle functies uit een module importeren met behulp van een
*(asterisk) - Wanneer alle functies worden geïmporteerd, kun je ze direct bij naam aanroepen
- Je hoeft dan geen puntnotatie meer te gebruiken (module.naam)
- Hoewel dit handig kan zijn, kan het ook onduidelijk worden welke functies waar vandaan komen
- Hieronder staat een voorbeeld met de Bitcoin-module
from bitcoin import *
show_price(41250)
convert_to_sats(0.0005)
De huidige Bitcoin prijs is: 41250 euro
0.0005 BTC is gelijk aan 50000 sats