# Programmeren in Python/Functies
## Wat zijn functies?

Bij het schrijven van code, zul je merken dat je vaak dezelfde code schrijft om taken uit te voeren. Functies laten je toe stukjes code die je regelmatig gebruikt te hergebruiken zodat je ze maar één keer hoeft te schrijven. Daarnaast kun je functies ook gebruiken om lange code op te splitsen in functies die elk hun eigen probleem oplossen. Dit heeft verschillende voordelen, het kan bijvoorbeeld de leesbaarheid van de code vergroten, aangezien iedere functie één probleem oplost en duidelijk is wat iedere functie doet en als er een fout in de code is kun je makkelijker opzoeken waar de fout ligt en hoef je enkel de functie te verbeteren die de fout bevat.
Python heeft al veel ingebouwde functies zoals b.v. input en output, maar het is dus ook mogelijk om zelf functies te definiëren. Als je een functie hebt gedefinieerd kun je die bewaren herhaaldelijk oproepen om te gebruiken.

## Functies definiëren, bewaren en oproepen
### Eenvoudig voorbeeld

Om een functie te definiëren moet je het sleutelwoord def gebruiken. Def staat in dit geval voor "definiëren".
Voorbeeld:
Python-code: mijn eerste functie
Output:
Zoals eerder gezegd moet je een functie definiëren met het sleutelwoord def, dit moet gevolgd worden met een zelf te kiezen naam gevolgd door haakjes en een dubbele punt :. De code voor de functie komt in een geïndenteerde blok.
Om een functie op te roepen moet je simpelweg de naam van de functie schrijven met de haakjes, dus my_first_function. De haakjes zorgt ervoor dat de functie wordt uitgevoerd.

### Functie oproepen vanuit een andere functie

Het is prima mogelijk om een functie op te roepen vanuit een andere functie.
Python-code: Functie oproepen vanuit een andere functie
output:

### Referenties naar een functie doorgeven

Net zoals een variabele, is de naam van een functie een verwijzing naar data in het geheugen. In dit geval is dat de data code die moet worden uitgevoerd. Je kunt de referentie kopiëren naar een andere variabele en vanuit die variabele de functie oproepen en laten uitvoeren.
Python-code: Referentie van een functie
In dit voorbeeld, werd de referentie van de functie my_first_function overgeplaatst naar de variabele function_in_variable. Omdat de haakjes niet worden gebruikt wordt de functie niet uitgevoerd. Vervolgens wordt de functie wel uitgevoerd met function_in_variable vanwege het vermelden van de haakjes.
Naast de referenties in variabele te plaatsen, kun je referenties ook bijvoorbeeld in lijsten plaatsen.
Python-code: Referentie van een functie
Output:

### Het gebruiken van pass

Soms kan het zijn dat je een functie wilt definiëren, maar dat je de code later wilt schrijven. Een functie moet echter code hebben in zijn geïndenteerde blok, het mag dus niet leeg zijn. Als je het volgende zou uitvoeren krijg je een foutmelding.
Python-code: pass
Output:
Om dit te verhelpen kun je het statement pass gebruiken als tijdelijke oplossing. pass is een statement dat niets doet, enkel het verhelpen van de IndentationError en gebruik je als volgt.
Python-code: pass

## Parameters en argumenten
### Eenvoudig voorbeeld

Het is mogelijk om parameters in te stellen wanneer je een functie definieert. Met parameters kun je argumenten (bijvoorbeeld variabelen) meegeven wanneer je een functie oproept. De functie kan dan met die argumenten aan de slag.
Python-code: argumenten
Output:

### Eenvoudig voorbeeld met meerdere parameters

Het is mogelijk om een functie te definiëren met meerdere parameters. Je kunt daardoor dus meerdere argumenten doorgeven aan je functie.
Python-code: argumenten
Output:
In dit voorbeeld zijn er dus twee parameters. Net zoals variabelen geef je een naam aan je functie wanneer je je functie definieert en net zoals bij variabelen kun je een naam slechts één keer gebruiken om een functie te definiëren. Als je toch een nieuwe functie definieert met dezelfde naam, zal de vorige functie worden overschreven. Als voorbeeld zullen we twee vorige voorbeelden combineren.
Python-code: argumenten
Output:
De eerste keer dat de functie hello_message werd opgeroepen waarbij we een voornaam en een achternaam als argumenten gaven was er geen probleem, de versie van de functie met twee parameters werd opgeroepen en correct uitgevoerd. De tweede keer toen we enkel de voornaam gaven kregen we een foutmelding. Dit komt dus omdat hij opnieuw de versie met twee parameters probeert uit te voeren. De versie met één parameter kan niet worden gebruikt omdat die werd overschreven door de tweede versie met slechts één parameter.
Een mogelijke oplossing is twee verschillende functies te definiëren, bijvoorbeeld hello_message_with_only_first_name en hello_message_with_first_and_last_name, maar dan definiëer je twee functies die eigenlijk hetzelfde doen. In de volgende voorbeelden zullen we zien hoe je op andere manieren parameters en argumenten kunt gebruiken om flexibeler met functies te kunnen werken.

### Standaard waarden

U kunt voor de parameters standaard waarden bepalen, die u kunt gebruiken in de functie als er geen argument is meegegeven toen de functie werd opgeroepen en uitgevoerd. Dit doet u door naast de naam van de parameter een = te schrijven gevolgd door een waarde. Dit kan een string zijn, een getal, etc...
Python-code: Standaardwaarden
Output:
In dit voorbeeld, hebben we eerst de functie opgeroepen met een argument die de waarde "Geert" heeft. De functie toonde dan het "Hallo bericht" met de naam "Geert". De tweede keer, toen we de functie opnieuw opriepen hebben we geen argument gegeven, dan wordt er aan de parameter de standaardwaarde gegeven en wordt die dan gebruikt. "Hallo Gebruiker".
U kunt een eenzelfde standaardwaarde instellen voor meerdere argumenten.

### Willekeurig aantal argumenten

Soms kan het zijn dat je niet weet hoeveel argumenten je gaat meegeven wanneer je een functie oproept. Als je dit niet weet kun je een * plaatsten voor de naam van de parameter.
Python-code: Willekeurig aantal argumenten
Output:
De argumenten die je doorgeeft komen in de functie terecht als een tuple, je zult die dan ook moeten verwerken als een tuple.

### Argumenten met sleutelwoorden

Python-code: argumenten
Output:

### Combineren

Het is mogelijk om gewone parameters, standaardwaarden, willekeurig aantal argumenten en argumenten via sleutelwoorden te combineren.

## Return

Tot nu toe hebben we met functies enkel simpele taken laten uitvoeren. Het handige aan functies is dat je het taken kan laten uitvoeren èn een resultaat kan laten terug geven. Dit kan met het sleutelwoord return.

### Eenvoudig voorbeeld

De volgende functie berekent de oppervlakte van een vierhoek en geeft het resultaat via het sleutelwoord return terug.
Python-code: return
Output:
Het is mogelijk om de expressie met de berekening rechtstreeks achter de return te plaatsen. De functie zal dan de berekening uitvoeren en het resultaat rechtstreeks terug sturen. Hierdoor bespaar je een regel code, maar heeft als nadeel dat het de leesbaarheid van de code kan verminderen bij complexere expressies.
Python-code: return

### Meerdere returns

Het is ook mogelijk om meerdere return statements te gebruiken in één functie. Maar slechts één zal worden gebruikt, namelijk de eerste die de functie tegenkomt als het wordt gebruikt.
Python-code: return
Output:

## Lambda expressies

Een lambda expressie is een naamloze of anonieme functie. Een lambda functie moet je niet definiëren met het sleutelwoord def, je moet ze geen naam geven en kun je in één regel opschrijven. Een lambda functie kan slechts één enkele regel code bevatten, en de structuur is de volgende: <functienaam>=lambda <argument(en)>:<return value>

### Eenvoudig voorbeeld

In onderstaand voorbeeld maken we een naamloze functie (lambda) aan die één optelt aan het argument x.
Python-code: lambda
Output:
Het sleutelwoord lambda wordt gebruikt om aan te geven dat we een lambda expressie gebruiken om een naamloze functie te definiëren.

### Lambda expressie als argument van een functie

Een lambda expressie kan als argument worden meegegeven wanneer een functie wordt opgeroepen. Hierdoor hoef je geen aparte functie nog definiëren. Dit is vooral handig als je het maar éénmalig nodig hebt. In onderstaand voorbeeld hebben we een lijst met verschillende namen, die we sorteren met de ingebouwde methode sort. In normale omstandigheden zal sort, de namen alfabetisch sorteren. De sort methode heeft een optionele parameter genaamd key, die we kunnen gebruiken om een alternatieve manier van sorteren te bepalen. We gebruiken deze parameter om een lambda als argument mee te geven. Als lambda expressie geven we het volgende mee, lambda x: len(x). Hier staat x voor een naam in de lijst. Met de ingebouwde functie len geven we het aantal tekens dat de naam heeft terug. De sort methode zal dan dit gebruiken als sleutel om te weten hoe hij de namen moet sorteren.
Python-code: Lambda expressie
Output:

## Recursieve functies

Recursieve functies zijn functies die zichzelf telkens weer opnieuw oproepen om een bepaalde bewerking te doen tot er aan een bepaalde voorwaarde is voldaan. Onderstaand voorbeeld is een recursieve functie die aftelt van een bepaald getal tot nul.
Python-code: Recursieve functies
Output:
In bovenstaand voorbeeld hebben we een functie gedefiniëerd genaamd count_down_from_number met als parameter een getal waarmee we starten met aftellen. Het print eerst het getal en zolang het getal groter is dan nul, roept de functie zichzelf op met als argument het getal min één. De functie zal dan blijven worden opgeroepen tot het getal nul geworden is en stopt dan ook de recursie.
In theorie kan een functie zich in het oneindige zichzelf oproepen, maar in Python gaat dit niet. Python zal na verloop van tijd zelf een recursie afbreken als het te vaak gebeurd.
Recursie kan ook gebruikt worden om de rij van Fibonacci te berekenen.
Python-code: Recursieve Fibonacci functie
Output: Dit programma drukt dus het 11e (10 +1) getal van de reeks van Fibonacci (=55) af.