← Python/Modules en tooling
Les 1 van 8
MODULE 09 · 01◷ 30 min

Code over echte modules verdelen

Na deze les kun je
  • Een eigen Pythonbestand als module importeren.
  • Namen uit verschillende modules uit elkaar houden.
  • Uitleggen waarom een import dezelfde module kan hergebruiken.

Je prijsberekening is bruikbaar in een factuur, maar ook in een besteloverzicht. Beide programma's dezelfde functie laten overschrijven geeft twee plekken om fouten te herstellen. Door de berekening in een eigen bestand te zetten, kun je dezelfde code vanuit verschillende programma's gebruiken.

Een bestand wordt een module

Een module is een eenheid met eigen namen, meestal afkomstig uit één Pythonbestand. Het bestand pricing.py kan bijvoorbeeld de functie subtotal bevatten. Vanuit een ander bestand laad je die module met import pricing.

De import geeft je de modulenaam; pricing.subtotal(...) zoekt vervolgens de functie in die module op. De punt betekent dus niet dat je een bestand opent bij iedere aanroep. Je benadert een naam in een al geladen Pythonobject.

In het eerste voorbeeld staan het startprogramma en de berekening in aparte bestanden. Bekijk beide bestanden voordat je het voorbeeld uitvoert: de functie staat alleen in de helpermodule.

Een startbestand gebruikt een losse helpermodule
main.py
import walking
print(walking.minutes(3, 12))
print(walking.__name__)
walking.py
def minutes(stages, minutes_per_stage):
    return stages * minutes_per_stage
Verwachte uitvoer
36
walking

De bestandsnaam bevat .py, maar de importnaam niet. import pricing.py betekent iets anders dan het bestand pricing.py importeren en geeft hier een fout. Gebruik import pricing, gevolgd door de naam die je nodig hebt.

Elke module bewaart haar eigen namen

Een naamruimte koppelt namen aan objecten. Twee modules mogen allebei een naam total hebben zonder elkaar daardoor te overschrijven. Met pricing.total is duidelijk in welke module je zoekt.

from pricing import subtotal bindt de gevonden functie rechtstreeks aan de naam subtotal in de importerende module. Dat maakt de aanroep korter, maar de herkomst is minder zichtbaar. De opdrachten gebruiken daarom voor de eigen prijsberekening de vorm pricing.subtotal.

Zo'n rechtstreekse import is geen levende koppeling naar de naam in de andere module. Als pricing.subtotal later een ander functieobject krijgt, houdt een eerder gebonden losse naam nog het oude object vast. Bij pricing.subtotal(...) wordt de modulenaam bij iedere aanroep opnieuw geraadpleegd.

Een bestaande standaardmodule gebruiken

Je hoeft niet iedere helper zelf te schrijven. De standaardbibliotheek levert modules mee met Python, waaronder math. De functie math.ceil geeft het kleinste gehele getal dat minstens zo groot is als de ontvangen waarde.

Voor bijvoorbeeld 2,3 benodigde dozen zijn drie hele dozen nodig. int(2.3) zou slechts twee geven; afkappen en naar boven afronden zijn verschillende bewerkingen. In deze les is de doosgrootte positief en hoef je geen extra invoervalidatie toe te voegen.

Een alias zoals import math as numbers verandert alleen de lokale naam voor hetzelfde moduleobject. De functies worden er niet door gekopieerd. Gebruik een alias wanneer die de code duidelijker maakt.

Waarom een tweede import niet opnieuw begint

Python bewaart geïmporteerde modules tijdens een interpreteruitvoering in sys.modules. Een volgende gewone import van dezelfde modulenaam gebruikt die opgeslagen module. Daardoor blijven bijvoorbeeld een gedeelde lijst en de functies van die module dezelfde objecten.

Twee imports delen dezelfde geladen module
main.py
import notes
import notes as other
notes.items.append('kaart')
print(notes is other)
print(other.items)
notes.py
print('notities geladen')
items = []
Verwachte uitvoer
notities geladen
True
['kaart']

Topniveaucode in de module draait bij de eerste import. Zet daar daarom geen werk dat je onbedoeld bij iedere gebruiker van de module wilt laten plaatsvinden. De volgende les laat zien hoe je een expliciet startpunt maakt.

Veelgemaakte fout: twee bestanden toch kopiëren

Een tweede definitie van subtotal in main.py wordt niet automatisch de functie uit pricing.py. Je hebt dan opnieuw twee losse implementaties. Laat de factuurfunctie de echte helpermodule gebruiken, zodat wijzigingen aan die helper ook in de factuur terechtkomen.

AAN DE SLAG 0/4
1

Een berekening in de helpermodule plaatsen

Maak subtotal(unit_price, quantity) in pricing.py. Geef het product van de twee gehele getallen terug, ook wanneer een waarde nul is. Houd deze functie in pricing.py en dupliceer haar niet in main.py.

2

Een tweede module de echte helper laten gebruiken

Maak invoice_total(unit_price, quantity, shipping) in main.py. Roep de huidige pricing.subtotal aan met unit_price en quantity, tel shipping bij het ontvangen resultaat op en geef die som terug.

3

De standaardbibliotheek voor afronden gebruiken

Maak boxes_needed(amount, box_size) in main.py. De invoer bestaat uit een niet-negatieve hoeveelheid en een positieve doosgrootte. Geef het aantal hele dozen terug door amount / box_size met math.ceil naar boven af te ronden; nul heeft nul dozen nodig.

4

Een functie via de actuele modulenaam ophalen

Maak current_pricer() in main.py. Geef het huidige functieobject pricing.subtotal terug zonder het aan te roepen. Ook als pricing.subtotal na de import vervangen wordt, moet een volgende aanroep dat nieuwe object teruggeven.

Onthoud dit

  • Een module heeft eigen namen die je via de modulenaam kunt benaderen.
  • Een importalias verwijst naar hetzelfde moduleobject.
  • Een gewone herhaalde import gebruikt tijdens dezelfde uitvoering de modulecache.

Hierna scheid je herbruikbare functies van code die alleen bij het starten van een programma moet draaien.

main.py
UitvoerPython
›
›_

Hier komt je resultaat.

Voer je code uit en ontdek
wat je hebt gemaakt.

0/4 stappen
EVEN MEEKIJKEN

Bekijk hoe het kan.

Je mag de oplossing bekijken. Deze poging telt dan niet mee als afgeronde les. Met Reset kun je daarna opnieuw zelf oefenen.