Werken met functies

Inleiding

Tot dusver heb je de code simpelweg in één bestand getypt en dat bestand direct uitgevoerd (vanuit Thonny). Voor kleine stukjes code werkt dit prima, maar zodra je uitgebreidere programma’s gaat schrijven wordt dit al snel onoverzichtelijk. Ook gebruik je dezelfde code vaak meermaals, die code op twee of meer plaatsen herhalen is inefficiënt en foutgevoelig.

In dit hoofdstuk leer je daarom eerst over functies. Een functie is een herbruikbaar stuk code, idealiter met één specifieke taak. Deze functie kun je vervolgens vaker aanroepen. Bijvoorbeeld:

namen = ["Ali", "Marie", "John", ]


# Definieer de functie `groet`
def groet(naam):
    print(f"Hallo, {naam}!")


# Roep `groet` aan voor elke naam in `namen`
for naam in namen:
    groet(naam=naam)

# Hallo, Ali!
# Hallo, Marie!
# Hallo, John!

Nu is dit een eenvoudig voorbeeld en is de winst die je behaalt ten opzichte van drie keer een print-statement uitschrijven wellicht niet zo groot. Maar stel je voor dat het een complexe berekening betreft, en de lijst bestaat niet uit drie elementen maar uit 100…​ Dan ervaar je al snel de voordelen van een herbruikbare functie!

Functies gebruik je dus om herhaling in je code te voorkomen, maar ook om je code te structureren. Naast het gebruik van functies zijn er nog meer manieren om je code te structureren, zoals werken in verschillende bestanden en mappen. Ook dat leer je in dit hoofdstuk.

Leerdoelen

Aan het eind van dit hoofdstuk:

  • Begrijp je wat een functie is

  • Begrijp je hoe functies helpen om je code te structureren

  • Begrijp je wat argumenten in een functie zijn

  • Begrijp je het verschil tussen positionele en sleutelwoordargumenten

  • Begrijp je hoe je argumenten optioneel maakt

  • Begrijp je wat en wanneer een functie iets teruggeeft

  • Begrijp je hoe je code in bestanden en mappen structureert

  • Begrijp je wat een import is en hoe dit werkt

Functies: een inleiding

Een functie is een stuk code dat je eerst definieert om later (meermaals) te gebruiken. Een functie kan optioneel argumenten hebben en kan optioneel een waarde teruggeven met return. In de basis ziet een functie er als volgt uit:

def kwadraat(getal):
    kwadraat = getal ** 2
    return kwadraat

Op regel één zie je dat een functie definitie begint met def (van define), gevolgd door een zelfgekozen naam. Na de naam volgen twee haakjes (()) met daarin optioneel één of meer argumenten. In dit geval is er één argument met de naam getal. De definitie sluit je af met een dubbele punt, waarna op regel twee het blok van de functie begint. Alle code in dit blok zal worden uitgevoerd als je de functie aanroept.

In de volgende paragrafen leer je meer over het werken met functies en hoe je ze gebruikt om je code te structureren.

Werken met functies

Nu je een basisbegrip hebt van functies, leer je in deze paragraaf hoe je met functies werkt.

Functies aanroepen

Bekijk nog eens de volgende eenvoudige functie:

def kwadraat(getal):
    kwadraat = getal ** 2
    return kwadraat

Als je het bestand met deze code uitvoert, zal er nog niets zichtbaars gebeuren. De functie is gedefinieerd, maar nog niet gebruikt. Daarvoor dien je de functie aan te roepen:

kwadraat(getal=10)  # Roep aan met naam van argument
kwadraat(10)  # Roep aan zonder naam van argument

Je ziet dat je de naam van het argument getal ook weg kunt laten. Verderop leer je hier meer over.

Voer je het bestand nu uit, dan zie je nog steeds niets zichtbaars gebeuren in Thonny (in de shell overigens wel). De functie geeft het resultaat terug met return, maar in dit geval wordt het resultaat nergens aan teruggegeven en 'verdwijnt' het.

Wijs je het resultaat toe aan een variabele, dan kun je er verder mee werken. Bijvoorbeeld het resultaat printen:

resultaat = kwadraat(getal=10)
print(resultaat)  # 100

Je kunt niet alleen het resultaat van een functie aan een variabele toewijzen, maar ook de functie zelf. Vervolgens kun je dan die variabele aanroepen:

mijn_functie = kwadraat
resultaat = mijn_functie(getal=10)
print(resultaat)  # 100

Omdat dit werkt, kun je een functie ook als argument meegeven aan een andere functie:

def kwadraat(getal):
    return getal ** 2

def bereken(berekening, getal):
    return berekening(getal=getal)

resultaat = bereken(berekening=kwadraat, getal=10)
print(resultaat)  # 100

De functie bereken ontvangt als eerste argument de functie kwadraat, die roep je vervolgens in het blok aan met het meegegeven getal. In je code moet je er wel voor zorgen dat de functie die als argument wordt meegegeven, de parameters heeft die je verwacht. Doe je dat niet, dan kunnen er fouten ontstaan, zoals hieronder:

def groet(naam):
    return f"Hallo, {naam}!"

def bereken(berekening, getal):
    return berekening(getal=getal)  # `groet` heeft geen argument `getal`

resultaat = bereken(berekening=groet, getal=10)  # Fout

Als je de functie bereken iets aanpast zodat hij geen sleutelwoordargument ontvangt (zie volgende paragraaf), dan gaat het wel goed, maar krijg je onverwachte resultaten:

def groet(naam):
    return f"Hallo, {naam}!"

def bereken(berekening, getal):
    return berekening(getal)  # Aangepast

resultaat = bereken(berekening=groet, getal=10)
print(resultaat)  # Hallo, 10!

Let er tot slot op dat je geen haakjes (()) gebruikt bij het meegeven als argument. Doe je dat wel, dan roep je de functie aan en geef je dus het resultaat mee.

Opdracht 1: Kwadraat

Neem de hierboven gedefinieerde functie kwadraat en schrijf een stuk code dat als resultaat een lijst met alle kwadraten van 1 tot en met 100 oplevert.

Tip: met getallen = range(1, 101) maak je een lijst met de getallen 1 tot en met 100.

Klik om het antwoord te tonen

Een mogelijke uitwerking is als volgt:

resultaat = []
for getal in range(1, 101):
    resultaat.append(kwadraat(getal=getal))

Argumenten in een functie

In deze paragraaf leer je meer over de argumenten in een functie.

Positionele argumenten en sleutelwoordargumenten

Eerder zag je al dat je één of meer argumenten kunt opgeven bij het definiëren van een functie. Deze argumenten dien je vervolgens ook op te geven als je de functie aanroept.

Het is aan de code die de functie aanroept of je de argumenten expliciet noemt of niet, onderstaande levert hetzelfde op:

def groet(naam):
    print(f"Hallo, {naam}")

groet("John")  # Hallo, Johnn
groet(naam="John") # Hallo, Johnn

Stel dat je de functie aanpast naar het groeten met voor- en achternaam:

def groet(voornaam, achternaam):
    print(f"Hallo, {voornaam} {achternaam}")

Wil je de functie nu aanroepen zonder de argumenten te benoemen, dan is het belangrijk de volgorde van de definitie aan te houden. Python zal namelijk de eerst opgegeven waarde koppelen aan het eerste argument, de tweede waarde aan het tweede argument, enzovoorts.

groet("John", "Doe")  # Hallo, John Doe
groet("Doe", "John")  # Hallo, Doe John

Roep je de functie op deze wijze aan, dan spreek je van positionele argumenten (omdat de positie uitmaakt).

Je kunt de functie ook aanroepen mét het benoemen van de argumenten. De volgorde maakt in dat geval niet meer uit:

groet(voornaam="John", achternaam="Doe")  # Hallo, John Doe
groet(achternaam="Doe", voornaam="John")  # Hallo, John Doe

Doordat je de argumenten expliciet koppelt aan de naam, maakt de volgorde niet uit, Python weet nu wat je bedoelt. Dit noem je sleutelwoordargumenten (keyword argument).

Je kunt positionele argumenten en sleutelwoordargumenten ook door elkaar gebruiken. Wel is het belangrijk dat sleutelwoordargumenten altijd na de positionele argumenten komen.

groet("John", achternaam="Doe")  # Hallo, John Doe
groet("Doe", voornaam="John")  # Werkt niet

In het laatste geval zul je een foutmelding krijgen dat voornaam tweemaal is opgegeven. De eerste waarde wordt automatisch aan het eerste argument (voornaam) gekoppeld. Nogmaals voornaam opgeven is dan niet mogelijk.

Optionele argumenten

In bovenstaande groet-functie zijn de twee argumenten voornaam en achternaam verplicht. Als je de functie aanroept met bijvoorbeeld alleen de voornaam, krijg je een foutmelding.

Er zijn situaties denkbaar waarbij je één of meer argumenten optioneel wil maken. Dit doe je door het een standaardwaarde toe te kennen bij het definiëren. Dit doe je door het argument te laten volgen door een is-teken (=), gevolgd door de standaard waarde.

def groet(naam, enthousiasme_niveau=1):
    uitroeptekens = "!" * enthousiasme_niveau
    print(f"Hallo, {naam}{uitroeptekens}")

groet("John")  # Hallo, John!
groet("John", enthousiasme_niveau=1)  # Hallo, John!
groet("John", enthousiasme_niveau=2)  # Hallo, John!!
groet("John", enthousiasme_niveau=0)  # Hallo, John

Zoals je ziet kun je de functie nu aanroepen met alleen een naam. In dat geval wordt er standaard één uitroepteken geplaatst. Je kunt dit nog steeds expliciet maken als je wil, door alsnog enthousiasme_niveau=1 mee te geven. Je kunt ook andere waarden toekennen.

Een ander veelgebruikte mogelijkheid is None als standaardwaarde mee te geven, en hier in het functieblok op te controleren:

def groet(voornaam, achternaam=None):
    volledige_naam = voornaam
    if achternaam:
        volledige_naam += " " + achternaam

    print(f"Hallo, {volledige_naam}.")

groet("John")  # Hallo, John.
groet("John", "Doe")  # Hallo, John Doe.
Opdracht 2: Begroeting

Maak een begroetingsfunctie die, naast de naam, een argument dagdeel accepteert. Begroet de persoon op de juiste wijze, bijvoorbeeld: Goedemorgen, John.. Als geen dagdeel wordt opgegeven, laat het dan weg uit de begroeting.

Klik om het antwoord te tonen

Een mogelijke uitwerking is als volgt:

def begroeting(naam, dagdeel=None):
    if dagdeel and dagdeel not in ["morgen", "middag", "avond"]:
        print("Dagdeel moet 'morgen', 'middag' of 'avond' zijn")

    else:
        if dagdeel:
            goede = "Goede"
            if dagdeel == "avond":
                goede += "n"
            print(f"{goede}{dagdeel}, {naam}")
        else:
            print(f"Hallo, {naam}")

De term parameter verwijst naar de namen bij het definiëren van de functie. De term argument verwijst naar het object dat je meegeeft aan de functie. In deze en andere hoofdstukken lees je in beide gevallen de term argument.

def groet(naam):  # `naam` is een parameter
    print(naam)

groet(naam="John")  # `John` is het meegegeven argument

Teruggeven van waarden uit een functie

In de meeste voorbeelden zag je dat de functie iets print. In de praktijk zul je een functie hiervoor niet vaak gebruiken, maar wil je dat de functie iets doet, en dan het resultaat teruggeeft. Dit teruggeven doe je met het sleutelwoord return.

def kwadraat(getal):
    kwadraat = getal ** 2
    return kwadraat

resultaat = kwadraat(getal=10)
print(resultaat)  # 100

Meerdere returns

Het teruggeven hoeft niet per se aan het einde van de functie, het kan bijvoorbeeld afhankelijk zijn van een if-else statement dat je terug geeft. Alle code na een uitgevoerde return wordt niet uitgevoerd.

def controleer_even_getal(getal):
    if getal % 2 != 0:
        return "Het opgegeven nummer is oneven."

    return "Het opgegeven nummer is even."


print(controleer_even_getal(7))  # Het opgegeven nummer is oneven.
print(controleer_even_getal(4))  # Het opgegeven nummer is even.

Als het getal oneven is, dan wordt de laatste return nooit bereikt.

In dit voorbeeld zie je de modulo-operator (%). Hiermee bereken je het restant van de deling van de twee getallen. Bijvoorbeeld: 10 % 2 levert 0 op, omdat twee vijf keer in 10 past. 9 % 2 levert 1 op, omdat 2 4 keer in 9 past, en je dan 1 overhoudt. Hiermee kun je dus eenvoudig berekenen of een getal even of oneven is.

None

In de voorbeelden waar alleen een print in de functie voorkwam, lijkt het alsof de functie niets teruggeeft. Het is echter zo dat Python aan het einde van de functie impliciet None teruggeeft wanneer je geen expliciete return opgeeft. Je kunt dit eenvoudig controleren:

def groet(naam):
    print(f"Hallo, {naam}")
    # Geen return

resultaat = groet(naam="John")
print(resultaat)  # None

Je mag ook zelf return None toevoegen, of korter: alleen return. Dit kun je gebruiken als je met bijvoorbeeld een if-else statement de functie vroegtijdig wil verlaten zonder waarde:

def controleer_even_getal(getal):
    if getal % 2 != 0:
        return

    return "Het opgegeven nummer is even."

In dit geval geeft de functie None terug als het getal oneven is.

Opdracht 3: Delen

Maak de volgende functie:

def deel_getallen(getal_1, getal_2):
    pass  # Vervang dit door je eigen code

Zorg ervoor dat het juiste resultaat wordt teruggegeven. Houd hierbij rekening met het feit dat je niet kunt delen door 0!

Klik om het antwoord te tonen

Een mogelijke uitwerking is als volgt:

def deel_getallen(getal_1, getal_2):
    if getal_2 == 0:
        return "Delen door 0 is niet mogelijk"

    return getal_1 / getal_2

Je code structureren met functies

Een functie kun je zien als een bouwsteen van je code. Met meerdere functies bouw je zo aan een uitgebreider programma. Het is raadzaam om je functies één verantwoordelijkheid te geven, dat houdt je code overzichtelijk en begrijpelijk. Geef je functienamen ook duidelijke, beschrijvende namen.

Net als bij de namen van variabelen zijn er een aantal regels voor en afspraken over functienamen. De regels zijn:

  • Gebruik alleen kleine- en hoofdletters (a tot en met z, A tot en met Z), underscores (_) en cijfers (0 tot en met 9)

  • Gebruik geen cijfer als eerste teken

De stijl-afspraak is om enkel kleine letters en underscores te gebruiken voor functienamen (ook wel snake_case genoemd). Bijvoorbeeld: mijn_functie.

Als eenvoudig voorbeeld zie je hieronder een programma dat de BMI van de gebruiker uitrekent.

def verkrijg_gegevens():
    """
    Vraag lengte en gewicht om de BMI te kunnen berekenen.
    """
    lengte = input("Wat is je lengte (in cm) ")
    gewicht = input("Wat is je gewicht (in kg)? ")

    lengte = int(lengte)
    gewicht = int(gewicht)

    return lengte, gewicht


def bereken_bmi(lengte, gewicht):
    """
    BMI: Gewicht in kg, gedeeld door het kwadraat van lichaamslengte in meters.
    """
    return gewicht / (lengte/100)**2


def main(naam):
    """
    Hoofdfunctie, bereken het BMI van de gebruiker.
    """
    print(f"Welkom bij de BMI-calculator, {naam}.\n")

    lengte, gewicht = verkrijg_gegevens()
    bmi = bereken_bmi(gewicht=gewicht, lengte=lengte)
    bmi = round(bmi, 2)

    print(f"\n{naam}, je BMI is {bmi}.\n")

main("John")  # Roep main aan

Je ziet dat er drie functies zijn gedefinieerd. De functie vraag_gegevens handelt het uitvragen van de persoonsgegevens af. De functie bereken_bmi handelt het berekenen van de BMI af. De laatste functie (main) voegt tot slot alles samen.

Er zijn een aantal zaken die opvallen:

Uitpakken In de functie verkrijg_gegevens worden twee variabelen teruggegeven, gescheiden door een komma. In de functie main worden deze variabelen uitgepakt. In Werken met tuples lees je nog eens over het uitpakken van tuples.

Duidelijkheid Elke functie heeft een duidelijke naam en een korte beschrijving van wat hij doet. Je hoeft enkel de functie main te lezen om te begrijpen wat er gaande is, zonder de inhoud van de overige functies te lezen.

Volgorde De volgorde van definiëren en aanroepen is relevant. In Python kun je pas iets aanroepen nadat het is gedefinieerd. Python leest elk bestand van boven naar beneden. Zou je main() naar boven verplaatsen, dan krijg je een foutmelding dat verkrijg_gegevens niet bestaat.

Je kunt de volgorde van de functies wel omdraaien. Pas op het moment dat je main() uitvoert, worden ook de andere functies aangeroepen, en op dat moment zijn ze al gedefinieerd. Het maakt dan niet uit dat bijvoorbeeld bereken_bmi eerder is gedefinieerd dan verkrijg_gegevens. Als beide maar beschikbaar zijn op het moment dat main wordt aangeroepen.

Opdracht 4: Rekenen

Maak vier functies die elk twee getallen accepteren:

  • delen

  • vermenigvuldigen

  • optellen

  • aftrekken

Maak een vijfde functie die ook twee getallen accepteert en de naam van het gewenste type berekening. Print het resultaat.

Klik om het antwoord te tonen

Een mogelijke uitwerking is als volgt:

# Defineer de berekeningsfuncties
def optellen(getal_1, getal_2):
    return getal_1 + getal_2

def aftrekken(getal_1, getal_2):
    return getal_1 - getal_2

def delen(getal_1, getal_2):
    if getal_2 == 0:
        return

    return getal_1 / getal_2

def vermenigvuldigen(getal_1, getal_2):
    return getal_1, getal_2


# De hoofdfunctie
def main(berekening, getal_1, getal_2):
    if berekening == "optellen":
        return optellen(getal_1, getal_2)
    elif berekening == "aftrekken":
        return aftrekken(getal_1, getal_2)
    elif berekening == "delen":
        return delen(getal_1, getal_2)
    elif berekening == "vermenigvuldigen":
        return vermenigvuldigen(getal_1, getal_2)
    else:
        return

Je code verder structureren

Je hebt geleerd dat je functies kunt gebruiken om je code op te delen in behapbare stukjes code, die je ook kunt hergebruiken. Als je programma groter wordt, zul je merken dat het handig is om je functies te verdelen over verschillende bestanden en mappen zodat je overzicht houdt. Hoe je dat doet leer je in deze paragraaf.

Je code structureren met modules (bestanden)

De eerste stap in het structureren van je code is vaak het verdelen over meerdere bestanden. Dergelijke bestanden heten in Python modules. Hoe je de bestanden indeelt is aan jou en hangt af van de context van het programma. Dit kan bijvoorbeeld op onderwerp of, type functionaliteit zijn.

Tot dusver heb je steeds gewerkt in één .py-bestand. Om de werking van modules te demonstreren maak je nu twee bestanden aan in dezelfde map: main.py en rekenen.py.

In Thonny kun je een nieuw bestand maken en opslaan, naast het bestand waar je al in werkt. Het nieuwe bestand opent in een nieuw tabblad, zodat je eenvoudig tussen beide bestanden kunt wisselen.

thonny meerdere bestanden
Meerdere bestanden in Thonny

In rekenen.py plaats je twee functies: kwadraat en getal_is_even.

def kwadraat(getal):
    kwadraat = getal ** 2
    return kwadraat


def getal_is_even(getal):
    if getal % 2 != 0:
        return False

    return True

Als je deze functies in main.py wil gebruiken, moet je ze importeren. Dit doe je met import. Hoewel het niet verplicht is, is het de gewoonte om dit bovenaan het bestand te doen. Er zijn twee manieren om de functies te importeren. Met de eerste manier importeer je de gehele module, en dus alle inhoud ervan, in één keer.

# main.py
import rekenen

Je gebruikt import met daarachter de naam van de module die je wil importeren. Je laat hierbij het achtervoegsel .py weg.

Vervolgens kun je de functies en andere gegevens uit rekenen.py gebruiken in main.py:

# main.py
import rekenen  # Importeer de gehele module `rekenen`

getal = 10
even_of_oneven = "oneven"

# Gebruik functie `kwadraat` uit module `rekenen`
kwadraat = rekenen.kwadraat(getal=getal)

# Gebruik functie `getal_is_even` uit module `rekenen`
is_even = rekenen.getal_is_even(getal=getal)

if is_even:
    even_of_oneven = "even"

print(f"Het kwadraat van {getal} is {kwadraat}. {getal} is een {even_of_oneven} getal.")

Je hebt de module rekenen als geheel geïmporteerd. Om hier nu iets uit te gebruiken is het nodig om de functienaam vooraf te laten gaan door rekenen, gescheiden door een punt. Doe je dit niet, dan zul je een fout krijgen omdat de functie niet in de huidige module is gedefinieerd.

Je kunt de functies die je nodig hebt ook direct importeren:

# main.py
from rekenen import kwadraat  # Importeer de functie `kwadraat` uit rekenen

# Gebruik functie `kwadraat` uit module `rekenen`.
# Deze is nu direct beschikbaar in `main`
kwadraat = kwadraat(getal=10)
print(kwadraat)  # 100

In dit geval heb je alleen de functie kwadraat nodig. Met from …​ import …​ geef je aan wat je precies uit welke module wil importeren. In het huidige bestand kun je nu direct de naam van de functie gebruiken, zonder de module te noemen.

Wil je meerdere functies importeren, dan kan dat ook:

# main.py
from rekenen import kwadraat, getal_is_even

Je scheidt de te importeren items dan door een komma.

Je code structuren met packages (mappen)

Net als met het werken met bijvoorbeeld foto’s op je computer, kun je de modules ook nog verder organiseren door ze in mappen te plaatsen. Deze mappen noem je packages.

Niet elke map is een package, je dient er eerst een Python-bestand met de bestandsnaam __init__.py in te plaatsen (aan beide kanten van init staan twee underscores). Dit is het bestand dat zal worden uitgevoerd als je de package importeert. Over het algemeen kun je het leeg laten. Maak in de map waar je in werkt, een nieuwe map functies aan, met daarin drie Python-bestanden:

  • __init__.py

  • begroetingen.py

  • rekenen.py (verplaats het voorgaande bestand naar deze map)

Plaats in begroetingen.py een eenvoudige groet functie.

def groet(naam):
    print(f"Hallo, {naam}.")

In dezelfde map als waar je de map functies hebt gemaakt, plaats je een bestand main.py.

modules packages structuur
Indeling van modules en package

Importeren werkt vrijwel hetzelfde als eerder, maar nu moet je ook aan geven uit welke package je wil importeren.

# main.py

# Importeer de gehele module `begroetingen` uit package `functies`
from functies import begroetingen

# Gebruik de functie `groet` uit de module `begroetingen`
begroetingen.groet(naam="John")
# Hallo, John.

Om alle functies van begroetingen te importeren (in dit geval is dat er maar één), gebruik je from …​ import …​. Je importeert nu begroetingen in zijn geheel, en alles is dus beschikbaar. Wel moet je je groet aan roepen met de module-naam begroetingen eraan voorafgaand.

Je kunt ook weer specifieke functies importeren:

# main.py

# Importeer de functie `kwadraat` uit de module `rekenen`, welke zich in
# de package `functies` bevindt.
from functies.rekenen import kwadraat

# Gebruik functie `kwadraat` uit module `rekenen`, nu direct beschikbaar in `main`
kwadraat = kwadraat(getal=10)
print(kwadraat)  # 100

Je ziet dat je weer de structuur from …​ import …​ gebruikt. Maar nu geef je op uit welke module (rekenen) uit welke package (functies) je wil importeren door beide te benoemen, gescheiden door een punt (dotted path): functies.rekenen.

Gebruik maken van de standaard bibliotheek

Naast dat je import kunt gebruiken om je eigen code te importeren, kun je het ook gebruiken om modules die standaard al aanwezig zijn in Python te importeren.

Python heeft een uitgebreide standaard bibliotheek. Hierin is allerlei functionaliteit beschikbaar, zodat je die niet zelf hoeft te programmeren. Te denken valt aan mathematische bewerkingen, werken met bestanden, werken met websites, en nog veel meer.

Bekijk de lijst met ingebouwde functionaliteit op docs.python.org/3/library/

Importeren werkt exact hetzelfde als met je eigen modules en packages:

from math import pi, floor

# Bereken oppervlakte cirkel (πr²)
straal_in_cm = 5
oppervlakte = pi * straal_in_cm**2

# Afkappen op geheel getal
oppervlakte = floor(oppervlakte)

print(f"De oppervlakte van een cirkel met een "
      f"straal van {straal_in_cm}cm "
      f"is ongeveer: {oppervlakte}cm")

Importeren en uitvoeren

Als je een bestand uitvoert vanuit de shell of Thonny, dan zal Python alle code in het bestand uitvoeren. Zodra het een import tegenkomt, zal het de import uitvoeren en de code in het geïmporteerde bestand ook uitvoeren.

Dit kan voor problemen zorgen als je een Python-bestand hebt dat je soms direct wil aanroepen, en soms wil gebruiken in een import. Neem het volgende voorbeeld, met twee bestanden bestand_1.py en bestand_2.py.

# bestand_1.py
import bestand_2

print(bestand_2.getal_is_even(10))

# 100
# True

# bestand_2.py
def kwadraat(getal):
    kwadraat = getal ** 2
    return kwadraat


def getal_is_even(getal):
    if getal % 2 != 0:
        return False

    return True

print(kwadraat(10))

In bestand_1 importeer je bestand_2 en print je het resultaat van de functie getal_is_even(10). In bestand_2 heb je echter nog een functie gedefinieerd (kwadraat) en voer je die uit op regel 21.

Voer je nu bestand_1 uit, dan zie je dat niet alleen True wordt geprint, maar ook 100, het resultaat van de code op regel 21 in de module bestand_2. Dit is het gevolg van het feit dat alle code wordt uitgevoerd door Python, ook bij het importeren.

Als je wil dat regel 21 van module bestand_2 alleen wordt uitgevoerd als bestand_2 direct wordt uitgevoerd en niet als het wordt geïmporteerd, moet je te weten dat Python op de achtergrond aan elk bestand dat wordt uitgevoerd een speciale variabele __name__ koppelt. Als je bestand_2 importeert, zal __name__ de waarde bestand_2 krijgen. Maar als je bestand_2 direct uitvoert, zal het de naam __main__ krijgen, omdat het dan wordt beschouwd als het entreepunt van je programma.

De variabelen __name__ en __main__ hebben aan beide kanten van het woord twee underscores.

Dit gegeven kun je gebruiken om code alleen uit te voeren als een module direct wordt uitgevoerd. Bekijk de wijziging in bestand_2:

# bestand_2.py

...

if __name__ == "__main__":
    print(kwadraat(10))

Voer je nu bestand_1 uit, dan wordt bestand_2 geïmporteerd en krijgt __name__ de waarde bestand_2. Omdat __name__ dus geen __main__ is, zal de functie niet worden uitgevoerd. Voer je bestand_2 direct uit, dan krijgt __name__ de waarde __main__ en zal de functie wel worden uitgevoerd.