6. De functies

6.1. Script [fonc_01]: bereik van variabelen
Het script [fonc_01] toont voorbeelden van het bereik van variabelen tussen functies:
# bereik van variabelen
def f1():
# het gebruik van globale variabelen moet worden vermeden
# globale variabele i
global i
i += 1
# lokale variabele j
j = 10
print(f"f1[i,j]=[{i},{j}]")
def f2():
# het gebruik van globale variabelen moet worden vermeden
# globale variabele i
global i
i += 1
# lokale variabele j
j = 20
print(f"f2[i,j]=[{i},{j}]")
def f3():
# lokale variabele i
i = 1
# lokale variabele j
j = 30
print(f"f3[i,j]=[{i},{j}]")
# hoofdprogramma
i = 0
j = 0
# deze twee variabelen zijn alleen bekend voor een functie f
# dan alleen als deze met de instructie `global` expliciet aangeeft dat ze deze wil gebruiken
# of dat de functie de globale variabele alleen in leesmodus gebruikt
f1()
f2()
f3()
# j is niet veranderd, maar i is wel veranderd
print(f"[i,j]=[{i},{j}]")
Resultaten
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_01.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
Opmerkingen:
- het script toont het gebruik van de variabele i, die in de functies f1 en f2 als globaal is gedeclareerd. In dit geval delen het hoofdprogramma en de functies f1 en f2 dezelfde variabele i.
6.2. Script [fonc_02]: bereik van variabelen
Het script [fonc_03] bouwt voort op het script [fonc_02] en laat zien hoe het gebruik van globale variabelen kan worden vermeden:
# bereik van variabelen
def f1(i):
# lokale variabele i
i += 1
# lokale variabele j
j = 10
print(f"f1[i,j]=[{i},{j}]")
# de gewijzigde waarde wordt teruggegeven
return i
def f2(i):
# lokale variabele i
i += 1
# lokale variabele j
j = 20
print(f"f2[i,j]=[{i},{j}]")
# de gewijzigde waarde wordt teruggegeven
return i
def f3():
# lokale variabele i
i = 1
# lokale variabele j
j = 30
print(f"f3[i,j]=[{i},{j}]")
# hoofdprogramma
i = 0
j = 0
# deze twee variabelen zijn alleen bekend voor een functie f
# alleen bekend zijn als deze met de instructie global expliciet aangeeft dat ze deze wil gebruiken
# of als de functie de globale variabele alleen in leesmodus gebruikt
i = f1(i)
i = f2(i)
f3()
# j is niet veranderd, maar i is wel veranderd
print(f"[i,j]=[{i},{j}]")
Opmerkingen:
- regels 2, 12: in plaats van als globale variabele te worden gedeclareerd, wordt de variabele [i] als parameter doorgegeven aan de functies f1 en f2;
- regels 9, 19: de functies f1 en f2 geven de gewijzigde variabele [i] terug aan het hoofdprogramma. Dit programma haalt de variabele op in de regels 36 en 37;
Resultaten
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_02.py
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[1,30]
[i,j]=[2,0]
Process finished with exit code 0
6.3. Script [fonc_03]: bereik van variabelen
Het script [fonc_03] laat een bijzonderheid zien van variabelen die zowel in een functie als in de code die deze functie aanroept worden gebruikt, afhankelijk van het feit of deze variabele in de functie uitsluitend als leesvariabele wordt gebruikt of niet.
def f1():
# hier is de globale variabele i bekend
print(f"[f1] i={i}")
# hier is de globale variabele j bekend
print(f"[f1] j={j}")
def f2():
# hier is de globale variabele i niet bekend
# omdat de functie f2 een lokale variabele met dezelfde naam definieert
# dan heeft deze voorrang
try:
# poging om de verderop gedefinieerde lokale variabele i weer te geven
print(f"[f2] i={i}")
# de volgende instructie maakt van i een lokale variabele van de functie f2
i = 7
except BaseException as erreur:
print(f"[f2] erreur={erreur}")
def f3():
# hier is de globale variabele i niet bekend
# omdat de functie f3 een lokale variabele met dezelfde naam definieert
# en die heeft dan voorrang
# de volgende instructie maakt van i een lokale variabele
i = 7
# weergave – hier is i bekend
print(f"[f3] i={i}")
# main -----------
# globale variabelen voor functies
i = 10
j = 20
# aanroep van f1
f1()
print(f"[main] i={i}, j={j}")
# aanroep van f2
f2()
print(f"[main] i={i}")
# aanroep van f3
f3()
print(f"[main] i={i}")
Opmerkingen
- regel 34: de hoofdcode definieert een variabele [i];
- regels 1-5: de functie f1 gebruikt ook een variabele [i] zonder deze een waarde te geven. Dit is een uitlezing van de variabele [i]. In dit geval is de gebruikte variabele [i] afkomstig uit de aanroepende code, regel 34;
- regels 8-18: de functie f2 gebruikt eveneens een variabele [i], maar wijst er in regel 16 een waarde aan. Door de variabele [i] in f2 een waarde te geven, wordt [i] automatisch een lokale variabele van de functie [f2]. Deze ‘verbergt’ dus de variabele [i] uit de aanroepende code;
- regel 14: het schrijven van de lokale variabele [i] zal mislukken omdat deze geen waarde heeft wanneer regel 14 wordt bereikt. Deze krijgt zijn waarde op regel 16. Er zal een uitzondering optreden. Om deze reden is regel 14 in een try/catch-blok geplaatst;
- regels 21-29: de functie f3 doet hetzelfde als de functie f2, maar definieert de lokale variabele [i] eerder;
Resultaten
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_03.py
[f1] i=10
[f1] j=20
[main] i=10, j=20
[f2] erreur=local variable 'i' referenced before assignment
[main] i=10
[f3] i=7
[main] i=10
Process finished with exit code 0
6.4. Script [fonc_04]: manier van doorgeven van parameters
Het script is als volgt:
# functie f1
def f1(a):
a = 2
# functie f2
def f2(a, b):
a = 2
b = 3
return a, b
# ------------------------ main
x = 1
f1(x)
print(f"x={x}")
(x, y) = (-1, -1)
(x, y) = f2(x, y)
print(f"x={x}, y={y}")
Resultaten
Opmerkingen:
- in Python is alles een object. Sommige objecten worden „immutable” (in het Engels) genoemd: deze kunnen niet worden gewijzigd. Dit geldt voor getallen, tekenreeksen en tuples. Wanneer Python-objecten als parameters aan functies worden doorgegeven, worden hun verwijzingen doorgegeven, tenzij deze objecten „immutable” zijn; in dat geval wordt de waarde van het object doorgegeven;
- de functies f1 (regel 2) en f2 (regel 7) zijn bedoeld om het doorgeven van een uitvoerparameter te illustreren. We willen dat de daadwerkelijke parameter van een functie door de functie wordt gewijzigd;
- regels 2-3: de functie f1 wijzigt haar formele parameter a. We willen weten of de effectieve parameter ook wordt gewijzigd;
- regels 14-15: de effectieve parameter is x=1. Uit regel 2 van de resultaten blijkt dat de effectieve parameter niet wordt gewijzigd. De effectieve parameter x en de formele parameter a zijn dus twee verschillende objecten;
- regels 8-10: de functie f2 wijzigt haar formele parameters a en b en retourneert deze als resultaten;
- regels 17-18: de effectieve parameters (x, y) worden doorgegeven aan f2 en het resultaat van f2 wordt teruggeplaatst in (x, y). Regel 3 van de resultaten laat zien dat de effectieve parameters (x, y) zijn gewijzigd.
Hieruit volgt dat wanneer „onveranderlijke” objecten als uitgangsparameters fungeren, deze deel moeten uitmaken van de resultaten die door de functie worden teruggegeven.
6.5. Script [fonc_05]: volgorde van functies in een script
Het script [fonc_05] laat zien dat een functie niet kan worden aangeroepen als deze niet eerder in de code is voorgekomen:
# ------------------------ main
print(f2(100, 200))
# functie f1
def f1(a):
return a + 10
# functie f2
def f2(a, b):
return f1(a + b)
Opmerkingen
- regel 2 zal een fout veroorzaken omdat deze de functie f2 gebruikt die nog niet in het script is gedefinieerd;
Resultaten
6.6. Script [fonc_06]: volgorde van functies in een script
Het script [fonc_06] laat zien dat wat geldt voor de aanroepende code, niet geldt voor de functies:
# functie f2
def f2(a, b):
return f1(a + b)
# functie f1
def f1(a):
return a + 10
# ------------------------ main
print(f2(100, 200))
Opmerkingen
- regel 3: de functie [f2] maakt gebruik van de functie [f1] die verderop in het script is gedefinieerd. Dit leidt echter niet tot een fout. We kunnen dus concluderen dat de volgorde waarin functies in een Python-script worden gedefinieerd, niet van belang is;
Resultaten
6.7. Script [fonc_07]: gebruik van modules
Het script [fonc_07] laat zien hoe functies in een module kunnen worden ondergebracht.

We isoleren herbruikbare functies in een module. In plaats van ze van het ene script naar het andere over te brengen:
- plaatsen we ze in een apart bestand dat we op een specifieke manier declareren;
- de scripts die deze functies nodig hebben, ‘importeren’ de module waarin ze zijn opgenomen;
Het script [fonctions_module_01] ziet er als volgt uit:
# functie f2
def f2(a, b):
return f1(a + b)
# functie f1
def f1(a):
return a + 10
Er zijn verschillende manieren waarop de functies van het script [fonctions_module_01] door andere scripts kunnen worden aangeroepen. Deze verschillen naargelang het script al dan niet binnen [PyCharm] wordt uitgevoerd.
In [PyCharm] wordt naar geïmporteerde modules gezocht in specifieke mappen met de naam [Sources Root]. Er zijn twee manieren om van een map een [Sources Root] te maken:

- in [4] is de kleur van de map gewijzigd;
Na deze bewerking wordt de map [fonctions/modules] herkend als een bronmap. Je kunt dan in een script schrijven:
Om de functie f2 te importeren/te gebruiken die is gedefinieerd in de module [fonctions_module_01.py].
![]() |
Een andere methode is via de projecteigenschappen:
- hierboven zorgt de reeks [1-6] ervoor dat de map [shared] een map wordt waarin te importeren modules kunnen worden opgeslagen;
We gaan voorlopig geen map als [Sources Root] aanmaken, behalve de hoofdmap van het project:

Zodra dit is gebeurd, kunnen we het volgende script [fonc-07] schrijven:
# gebruik van modules
import sys
# ------------------------ main
print(f"Python path={sys.path}")
from fonctions.shared.fonctions_module_01 import f2
print(f2(100, 200))
- regel 2: we importeren het object [sys] om gebruik te kunnen maken van regel 5, namelijk het attribuut [path], dat het zogenaamde [Python Path] oplevert: een lijst met mappen die worden doorzocht op geïmporteerde modules;
- regel 6: we importeren de functie f2 uit de module [fonctions_module_01]. Om deze module aan te duiden, gebruiken we het pad dat van de projectroot naar de module leidt. In PyCharm maakt de projectroot altijd deel uit van de mappen die worden doorzocht wanneer in een script naar een geïmporteerde module wordt gezocht. Deze map maakt dus deel uit van de [Python Path] van het project. Dit is wat we met regel 5 kunnen controleren;
- regel 6: als we het pad zouden beschrijven dat van de projectroot naar de map [fonctions_module_01] leidt, zouden we [fonctions/shared/fonctions_module_01] schrijven. In het pad van een module wordt het teken / vervangen door een punt. We schrijven dus [fonctions.modules.fonctions_module_01];
- na regel 6 is de functie f2 bekend. Deze wordt gebruikt in regel 8;
Resultaten
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_07.py
Python path=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
310
Process finished with exit code 0
Hierboven:
- groen gemarkeerd, zien we dat de hoofdmap van het project deel uitmaakt van [Python Path];
- geel gemarkeerd is te zien dat de map van het uitgevoerde script ook deel uitmaakt van [Python Path];
- de overige elementen van [Python Path] zijn rechtstreeks afkomstig uit de installatiemap van Python;
Wat gebeurt er als PyCharm niet wordt gebruikt om [fonc-07] uit te voeren?


- in [1] wordt het script [fonc-07] uitgevoerd. We bevinden ons in de map [fonctions];
- in [2] zien we dat de uitvoermap deel uitmaakt van [Python Path]. Dit is altijd het geval. We zien ook dat de hoofdmap [C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020] geen deel uitmaakt van [Python Path];
- in [3] meldt de Python-interpreter dat hij de module [fonctions] niet kan vinden;
Om de geïmporteerde module [fonctions.shared.fonctions_module_01] te vinden, zoekt de Python-interpreter in de mappen van [Python Path] naar een submap met de naam [fonctions]. Hij vindt deze nergens. De submap [fonctions] bevindt zich namelijk in de map [C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020], die geen deel uitmaakt van [Python Path].
Het script [fonc-08] biedt een mogelijke oplossing voor dit probleem.
6.8. Script [fonc_08]: mappen toevoegen aan [Python Path]
Het is mogelijk om het script [Python Path] programmatisch aan te passen, zoals te zien is in het script [fonc-08]:
# gebruik van modules
import os
import sys
# scriptmap
script_dir = os.path.dirname(os.path.abspath(__file__))
# Python Path vóór wijziging
print(f"Python path avant={sys.path}")
# de map [shared] wordt toegevoegd aan het Python-pad
sys.path.append(f"{script_dir}/shared")
# Python-pad na wijziging
print(f"Python path après={sys.path}")
# import f2
from fonctions_module_01 import f2
# ------------------------ main
print(f2(100, 200))
Opmerkingen
- regel 4: de speciale variabele [__file__] is de naam van het script dat wordt uitgevoerd. Afhankelijk van de uitvoeringscontext kan deze naam absoluut (Pycharm) of relatief (console) zijn. De functie [os.path.abspath] geeft de absolute naam van het bestand waarvan de naam wordt doorgegeven. De functie [os.path.dirname] geeft de absolute naam van de map die het bestand bevat waarvan de naam wordt doorgegeven;
- regel 10: [sys.path] is een array met de namen van de mappen die moeten worden doorzocht wanneer er naar een module wordt gezocht. Aan deze array wordt de in regel 4 gedefinieerde projectroot toegevoegd;
- we geven de [Python Path] weer vóór (regel 8) en na (regel 12) de wijziging;
- regel 15: de module [fonctions_module_01], die de functie f2 bevat, wordt geïmporteerd;
De uitvoering in PyCharm levert de volgende resultaten op:
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/fonctions/fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions\\shared', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
Process finished with exit code 0
- regel 3: we zien dat het dossier [shared] twee keer voorkomt in het dossier [Python Path]. Dit kan worden voorkomen, maar in dit geval is het geen probleem;
- regel 4: de functie f2 is inderdaad uitgevoerd;
Laten we nu [fonc-08] uitvoeren in een terminal:
(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\fonctions>python fonc_08.py
Python path avant=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages']
Python path après=['C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions', 'C:\\myprograms\\Python38\\python38.zip', 'C:\\myprograms\\Python38\\DLLs', 'C:\\myprograms\\Python38\\lib', 'C:\\myprograms\\Python38', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\venv\\lib\\site-packages', 'C:\\Data\\st-2020\\dev\\python\\cours-2020\\python3-flask-2020\\fonctions/shared']
310
- regel 2: net als eerder staat de map [shared] niet in [Python Path];
- regel 3: nu staat het er wel in;
- regel 4: de functie f2 is gevonden;
6.9. Script [fonc_09]: declaratie van het type van de parameters
Het script [fonc_09] laat zien dat je het type van de parameters van een functie en dat van het resultaat kunt declareren. Deze declaratie is echter alleen nuttig voor de documentatie van de functie. De Python-interpreter controleert niet of de daadwerkelijke parameters van de functie inderdaad het verwachte type hebben. Pycharm signaleert echter type-inconsistenties tussen daadwerkelijke en formele parameters. Alleen al om deze reden zijn typedeclaraties onmisbaar.
Het script ziet er als volgt uit:
# een functie met vermelding van het type van de parameters
# dit dient uitsluitend als documentatie, aangezien de Python-interpreter hier geen rekening mee houdt
def show(param: int) -> int:
print(f"param={param}, type(param)={type(param)}")
return param + 1
# main -------------------------
print(show(4))
show("xyz")
Opmerkingen:
- regel 5: hier wordt aangegeven dat de formele parameter [param] van het type [int] is en dat het resultaat van de functie eveneens van het type [int] is;
- regel 11: de werkelijke parameter van de functie [show] heeft het juiste type;
- regel 12: de daadwerkelijke parameter van de functie [show] heeft niet het juiste type;
Resultaten
- regel 10: het type van de parameter [param] is van het type [str]. Wanneer dit bericht verschijnt, is men al in de code van de functie [show] terechtgekomen. De Python-interpreter heeft dus geaccepteerd dat de daadwerkelijke parameter van de functie [show] van het type [str] is;
- regel 7 van de code veroorzaakt de uitzondering die wordt weergegeven in de regels 4-10 van de resultaten;
PyCharm geeft echter aan dat er een afwijking is:

In [1] heeft PyCharm de foutieve aanroep gemarkeerd.
6.10. Script [fonc_10]: benoemde parameters
Om parameters door te geven aan een functie, kun je de namen van de formele parameters van die functie gebruiken. In dat geval hoef je de volgorde van de formele parameters niet aan te houden:
# de daadwerkelijke parameters kunnen worden aangeduid met hun formele namen
def f(x, y):
return x + y
# main
print(f(y=10, x=3))
Opmerkingen
- regel 2: de functie f heeft twee formele parameters x en y;
- regel 7: bij het aanroepen van de functie f kunnen de namen van de formele parameters worden gebruikt. Dit kan in ten minste twee gevallen nuttig zijn:
- de functie heeft veel parameters, waarvan de meeste een standaardwaarde hebben. Bij het aanroepen maakt de bovenstaande techniek het mogelijk om alleen die parameters te initialiseren waarvan men de standaardwaarde niet wil gebruiken;
- als de formele parameters een betekenisvolle naam hebben, verbetert het gebruik van benoemde parameters bij het aanroepen van de functie de leesbaarheid van de code;
Resultaten
6.11. Script [fonc_11]: recursieve functie
Het script [fonc_11] is een voorbeeld van een recursieve functie (die zichzelf aanroept):
# recursieve functie
def fact(i: int) -> int:
# factorial(1) is 1
# een recursieve functie moet op een bepaald moment eindigen
if i == 1:
return 1
else:
# factorial(i) = i * factorial(i-1)
return i * fact(i - 1)
# ---------- main
print(f"fact(8)={fact(8)}")
Opmerkingen
- regels 1-9: de factorialfunctie;
- regel 9: de functie [factorielle] roept zichzelf aan;
- regels 5-6: een recursieve functie moet altijd stoppen wanneer aan een voorwaarde is voldaan, anders ontstaat er een oneindige recursie;
Resultaten
6.12. Script [fonc_12]: recursieve functie
De functie [fonc_12] geeft meer details over de werking van recursie:
# recursieve functie
# gedrag van de parameter j
def fact(i: int, j: int) -> int:
# beëindiging van de recursieve functie
if i == 1:
print(f"j={j}")
return 1
else:
# j wordt gemanipuleerd
j += 1
print(f"avant fact j={j}")
# recursiviteit
f = fact(i - 1, j)
print(f"après fact j={j}")
# resultaat
return i * f
# ---------- main
print(f"fact(8)={fact(8, 0)}")
Opmerkingen
- regel 5: we houden ons nog steeds bezig met de faculteitsfunctie. We voegen de parameter [j] toe;
- regel 12: de variabele j wordt bij elke faculteit met één verhoogd. We geven de waarde ervan weer vóór (regel 12) en na (regel 16) de recursie (regel 15);
Resultaten
- regels 2-8: we zien dat de waarde van [j] toeneemt zolang de recursie doorgaat, totdat de voorwaarde wordt bereikt waarbij de recursie stopt. Vanaf dat moment verloopt de terugkeer van de aanroepen naar de functie [fact] in omgekeerde volgorde van de aanroepen;
- regels 10-16: deze weergaven geven de opeenvolgende terugkeringen van de aanroep van de faculteit weer. De variabele [j] keert terug naar zijn waarden tot aan de beginwaarde 1;
