Modules en debuggen in Python: fouten zoeken en testen

Leer voortbouwen op bestaande code en je eigen code betrouwbaar laten werken. Importeer modules uit de standaardbibliotheek van Python, zoals math en random, schrijf je eigen modules en installeer pakketten van PyPI met pip. Lees daarna stacktraces en foutmeldingen, zoek programmeerfouten met een stapsgewijze aanpak en controleer je functies met assert-instructies en je eerste unittests.

BeginnerLes 9 van 10 in Cursus Inleiding tot programmeren met Python

Wat je leert

  1. Importeer bestaande code in een programma met import-instructies, gebruik modules uit de standaardbibliotheek zoals math en random, verdeel je eigen code over modules en installeer pakketten van derden met pip.
    • Importeer code in een programma met import-instructies
      Gebruik import, from … import en as correct, benader namen met puntnotatie en maak onderscheid tussen importfouten.
    • Reken en simuleer met math, random en andere standaardmodules
      Gebruik de belangrijkste functies van math en random, vermijd veelvoorkomende valkuilen en leer enkele andere veelgebruikte modules uit de standaardbibliotheek kennen.
    • Schrijf en importeer je eigen modules
      Verdeel code over je eigen .py-bestanden, importeer ze, voorkom naamconflicten en gebruik if __name__ == "__main__": zodat een bestand zowel kan worden uitgevoerd als geïmporteerd.
    • Installeer en beheer pakketten met pip
      Installeer, bekijk, update en verwijder pakketten van derden van PyPI, importeer ze onder de juiste naam en los veelvoorkomende installatieproblemen op.
  2. Gebruik de foutuitvoer van Python om te vinden waar en waarom een programma is mislukt, en maak onderscheid tussen syntaxisfouten, uitvoeringsfouten en logische fouten.
    • Lees een stacktrace van onder naar boven
      Zoek het exceptietype, de melding, de regel waar de fout optrad en de aanroepketen die daartoe leidde.
    • Herken veelvoorkomende fouten en hun oorzaken
      Koppel de meest voorkomende exceptietypen aan hun gebruikelijke oorzaken en oplossingen, en herken logische fouten die geen melding geven.
  3. Zoek de oorzaak van een programmeerfout met een stapsgewijze aanpak in plaats van te gokken, en onderzoek een draaiend programma met print-instructies en een debugger.
    • Volg een stapsgewijze aanpak om te debuggen
      Reproduceer een programmeerfout, vorm en toets een hypothese, baken de oorzaak af, herstel die en test opnieuw.
    • Onderzoek een programma met print-instructies, uitvoeringstabellen en een debugger
      Bekijk hoe waarden veranderen terwijl code wordt uitgevoerd, door print-instructies toe te voegen, de uitvoering met de hand te volgen of bij onderbrekingspunten te pauzeren.
  4. Gebruik assert om vast te leggen wat waar moet zijn, schrijf kleine geautomatiseerde tests voor je functies en voer ze uit en lees ze met de standaardmodule unittest.
    • Controleer aannames met assert-instructies
      Schrijf assert-instructies met duidelijke meldingen en weet wanneer asserties wel en niet het juiste hulpmiddel zijn.
    • Schrijf je eerste unittests voor je functies
      Schrijf testfuncties met asserties, kies typische gevallen, grensgevallen en randgevallen en gebruik mislukte tests om programmeerfouten te vinden en te herstellen.
    • Organiseer tests en voer ze uit met unittest
      Schrijf tests met unittest.TestCase, voer ze uit en lees het verslag van geslaagde en mislukte tests en testfouten.

Modules en debuggen in Python: uitleg

4 hoofdstukken

1

Hergebruik modules en installeer pakketten

Met geïmporteerde code kan een klein programma berekeningen, simulaties en hulpmiddelen gebruiken die elders zijn geschreven. Je kiest een importvorm, werkt met functies uit de standaardbibliotheek en organiseert je eigen functies zodat een ander bestand ze kan hergebruiken. Bij installeren komt een aparte vraag kijken: welke Python krijgt een pakket van derden? Als je dat verband begrijpt, kun je gemakkelijker een ontbrekende module onderzoeken en de namen in elk programma duidelijk houden.

1.1 Importeer een module of geselecteerde namen

Een module bevat Pythoncode die een ander programma kan hergebruiken. De meeste modules zijn .py-bestanden. De standaardbibliotheek wordt met Python meegeleverd; code van derden moet je afzonderlijk installeren. Een pakket groepeert verwante modules, meestal in een map.

Stem de aanroep af op de import

Een import maakt namen aan in je programma. De vorm die je kiest, bepaalt hoe je de geïmporteerde code aanroept.

InstructieAangemaakte naamVoorbeeldaanroep
import mathmathmath.sqrt(16)
from math import sqrtsqrtsqrt(16)
import statistics as statsstatsstats.mean([2, 4, 9])
from random import randint as rollrollroll(1, 6)

Puntnotatie betekent dat je een naam opzoekt binnen een module of object. In math.sqrt(16) vindt Python sqrt binnen math en roept die functie aan met 16. Het resultaat is 4.0. De constante math.pi heeft geen aanroephaakjes nodig, omdat het een waarde is en geen functie.

Na import math werpt alleen sqrt(16) de exceptie NameError op: het programma heeft een naam voor de module, maar geen afzonderlijke naam voor sqrt. Na alleen from math import sqrt werpt de omgekeerde fout, math.sqrt(16), ook NameError op omdat math niet is gebonden. Een alias geeft de geïmporteerde binding een andere naam dan de gebruikelijke: import statistics as stats maakt stats aan, niet beide namen.

Voer dezelfde berekening op twee manieren uit

Een rechthoekige driehoek heeft zijden van 3 en 4. Kwadrateer eerst de zijden en tel ze op; neem daarna de vierkantswortel.

import math

length = math.sqrt(3**2 + 4**2)
print(length)  # 5.0

De expressie binnen de aanroep wordt 9 + 16, daarna 25; sqrt geeft 5.0 terug. Met from math import sqrt schrijf je in plaats daarvan length = sqrt(3**2 + 4**2). Het modulevoorvoegsel maakt de herkomst van een functie zichtbaar en houdt de andere namen uit de naamruimte van je programma. De binding math zelf kan nog steeds een eerdere variabele met de naam math vervangen.

Houd namen duidelijk

Vermijd from math import *. Deze import met een jokerteken haalt openbare namen naar je programma zonder ze afzonderlijk te noemen. Zo verandert e = 5, gevolgd door die import, e in 2.718281828459045. Een import die er los van lijkt te staan kan daardoor een latere berekening veranderen. PEP 8 beveelt expliciete imports aan en plaatst imports bovenaan, met één module per regel: eerst de standaardbibliotheek, daarna pakketten van derden en ten slotte je eigen modules.

Python voert de code op moduleniveau van een module uit bij de eerste import tijdens een programma-uitvoering. Latere imports hergebruiken de geladen module; ze starten die niet opnieuw.

Kies de oplossing aan de hand van de fout
FoutWat je controleert
ModuleNotFoundError door import mathhDe spelling en installatie van de module
ImportError door from math import square_rootDe naam die uit de module wordt gevraagd
AttributeError door math.sqroot(16)De naam na de punt

Voer in de interactieve shell import math uit en daarna dir(math) om de namen weer te geven. Voer help(math.sqrt) uit om de documentatie van een functie te lezen. De officiële Pythonbibliotheekdocumentatie legt de argumenten en het resultaat uit.

Belangrijkste punten

  • import module maakt een modulebinding aan; benader de inhoud met puntnotatie.
  • from module import name maakt de geselecteerde binding aan; met as kies je een alias.
  • Expliciete imports houden de herkomst van namen duidelijk en verkleinen de kans op onbedoelde vervanging.
  • Importfouten maken onderscheid tussen een niet-gevonden module, een niet-beschikbare geïmporteerde naam en een ontbrekend attribuut.
  • dir() geeft namen weer; help() legt uit hoe je er één gebruikt.

1.2 Kies functies uit math en random

De standaardbibliotheek biedt geteste hulpmiddelen voor berekeningen en simulaties. Bij de keuze van een functie ga je uit van het resultaat dat je nodig hebt: een geheel aantal, een afgeronde meetwaarde, één willekeurig element of een lijst in een andere volgorde.

Afronden heeft meerdere betekenissen

Na import math geeft math.sqrt(16) het zwevendekommagetal 4.0 terug. math.pi en math.e leveren de constanten 3.141592653589793 en 2.718281828459045. math.factorial(5) vermenigvuldigt de gehele getallen van 1 tot en met 5 en geeft 120 terug.

ExpressieResultaatBetekenis
math.floor(7.9)7Grootste gehele getal dat niet groter is dan de waarde
math.ceil(2.1)3Kleinste gehele getal dat niet kleiner is dan de waarde
math.floor(-2.5)-3Naar beneden gaat in de richting van min oneindig
int(-3.5)-3De conversie kapt af in de richting van nul
round(2.5)2Een waarde precies halverwege wordt naar even afgerond
round(3.5)4Het dichtstbijzijnde even gehele getal is 4

Voor 23 vierkante meter muur en 10 vierkante meter per verfblik geeft de deling 2.3 blikken. Als je hele blikken koopt, heb je math.ceil(23 / 10) nodig, wat 3 teruggeeft. round(2.3) geeft 2 en levert te weinig verf op.

De ingebouwde functie round() hoef je niet te importeren. Voor een cirkel met straal 2 geeft round(math.pi * 2 ** 2, 2) de waarde 12.57. Afronden verandert de precisie van een getal; dat is iets anders dan genoeg hele verpakkingen kopen.

Controleer domeinen en vergelijkingen van zwevendekommagetallen

math.sqrt(-1) werpt ValueError op omdat er voor die invoer geen reële vierkantswortel bestaat. Ook bij berekende zwevendekommagetallen moet je opletten: door de binaire opslag is 0.1 + 0.2 == 0.3 gelijk aan False. math.isclose(0.1 + 0.2, 0.3) is True; gebruik dit om berekende zwevendekommagetallen bij benadering te vergelijken.

Kies de willekeurige bewerking

De module random gebruikt een algoritme om pseudowillekeurige resultaten te maken.

AanroepResultaat
random.randint(1, 6)Een geheel getal van 1 tot en met 6, beide inbegrepen
random.randrange(1, 6)Een geheel getal van 1 tot en met 5
random.random()Een zwevendekommagetal van minstens 0,0 en kleiner dan 1,0
random.uniform(a, b)Een zwevendekommagetal tussen de opgegeven grenzen
random.choice(items)Eén element
random.sample(items, k)Elementen van k posities, zonder terugleggen
random.shuffle(items)Verandert de volgorde van de bestaande lijst; geeft None terug

Zet random.shuffle(cards) op een eigen regel. Als je het resultaat weer aan cards toekent, verlies je de binding met de lijst doordat je die vervangt door None. Posities trekken is ook iets anders dan verschillende waarden vereisen: random.sample([1, 1], 2) geeft [1, 1] terug.

Voer een herhaalbare simulatie uit
import random

sevens = 0
for _ in range(1000):
    if random.randint(1, 6) + random.randint(1, 6) == 7:
        sevens += 1
print(sevens)

Zes van de 36 even waarschijnlijke paren hebben als som 7, dus het aantal ligt meestal rond 167, maar verschilt per uitvoering. Om bij het debuggen een reeks te reproduceren, roep je random.seed(42) aan voordat je de waarden genereert, met dezelfde Pythonversie en aanroepvolgorde. Gebruik voor wachtwoorden of beveiligingstokens secrets.

Vind andere veelgebruikte hulpmiddelen

statistics.mean([2, 4, 9]) geeft 5 terug; statistics.median([2, 4, 9]) geeft 4 terug. datetime.date.today() geeft de datum van vandaag. Na import sys bevat sys.argv de scriptnaam gevolgd door de argumenten: als je python greet.py Ada uitvoert, levert dat ['greet.py', 'Ada'] op.

Belangrijkste punten

  • floor, ceil, int en round beantwoorden verschillende vragen over afronden.
  • Gebruik math.isclose wanneer je berekende zwevendekommagetallen vergelijkt.
  • randint bevat beide grenzen; randrange sluit de eindgrens uit.
  • sample kiest posities zonder terugleggen, dus dubbele invoerwaarden kunnen worden herhaald.
  • shuffle verandert een lijst ter plaatse en geeft None terug.
  • Een vaste startwaarde helpt willekeurig gedrag te reproduceren; voor beveiligingstokens is secrets nodig.

1.3 Maak een bestand herbruikbaar zonder het programma te starten

Een functie is gemakkelijker te hergebruiken als die in een module met een duidelijke taak staat. Een ander programma kan die functie importeren en een test kan haar controleren zonder iemand te vragen de hele toepassing uit te voeren.

Scheid de functie van de aanroepende code

Sla deze code op als geometry.py:

"""Calculations for simple shapes."""
import math

def circle_area(radius):
    """Return the area of a circle with the given radius."""
    return math.pi * radius ** 2

Sla in dezelfde map deze aanroepende code op als main.py:

import geometry

print(geometry.circle_area(2))

Voer python main.py uit. Python vindt geometry, maakt de functie aan en daarna voert de aanroepende code die functie uit. Het afgedrukte resultaat is 12.566370614359172. Importeer zonder de uitgang .py. Een geldige modulenaam gebruikt letters, cijfers en underscores, met een geldig eerste teken; my_tools.py werkt met import my_tools, terwijl import my-tools ongeldige syntaxis is.

De strings aan het begin van de module en de functie zijn docstrings. Ze beschrijven het doel van de code en verschijnen in help(geometry) en help(geometry.circle_area).

Begrijp wat een import uitvoert

Bij de eerste import voert Python de instructies op moduleniveau op volgorde uit. Een def-instructie maakt een functie aan; ze voert de inhoud van die functie niet uit. Een onbeschermde print(circle_area(2)) onderaan geometry.py zou echter tijdens het importeren iets afdrukken.

Dat neveneffect is van belang wanneer een module invoervragen of een programmalus bevat. Een test die alleen circle_area nodig heeft, zou niet het programma hoeven te starten en de invoervragen hoeven te beantwoorden.

Bescherm de start en houd de functie beschikbaar

Voeg dit onder de herbruikbare functie toe in geometry.py:

def main():
    print(circle_area(2))

if __name__ == "__main__":
    main()

Python stelt __name__ in voor elke module. Bij directe uitvoering, python geometry.py, krijgt die variabele de waarde "__main__", waardoor de voorwaarde waar is en main() wordt aangeroepen. Bij het importeren van geometry krijgt ze de waarde "geometry", zodat Python de aanroep overslaat. De definities boven de voorwaarde blijven in beide gevallen beschikbaar.

Plaats circle_area zelf niet binnen de voorwaarde. Wie de module importeert, heeft die definitie ook nodig als de startvoorwaarde onwaar is. De voorwaarde bepaalt wanneer de toepassing start; ze verhindert niet dat Python de module laadt.

Weet waar Python zoekt

Python controleert ingebouwde modules zoals sys en daarna op volgorde de mappen in sys.path. Normaal gesproken staat de map van het uitgevoerde script als eerste op dat pad, gevolgd door mappen van de standaardbibliotheek en geïnstalleerde pakketten. Je eigen bestanden naast het uitgevoerde script bewaren is een eenvoudige indeling voor een beginnersproject. Een module buiten het zoekpad kan niet met een gewone import worden gevonden.

Door deze volgorde kan ook een bibliotheekmodule worden verborgen. Als je je programma opslaat als random.py, kan de instructie import random je eigen bestand laden in plaats van de bibliotheek. Een latere random.randint(1, 6) werpt dan AttributeError op. Geef het bestand een andere naam, bijvoorbeeld dice.py; Python 3.13 en later kunnen in de foutmelding een aanwijzing geven om het bestand te hernoemen.

Een geladen module wordt binnen dezelfde uitvoering hergebruikt. Als je in een interactieve shell het bestand bewerkt en opnieuw importeert, blijft de geladen versie behouden. Start de shell opnieuw voordat je je wijzigingen test.

Belangrijkste punten

  • Importeer je eigen .py-bestand met de modulenaam zonder extensie.
  • Een import voert instructies op moduleniveau uit, terwijl functie-inhoud wacht op een aanroep.
  • Houd herbruikbare definities buiten de __main__-voorwaarde en de start van het programma daarbinnen.
  • Een lokaal bestand kan een bibliotheekmodule met dezelfde naam verbergen.
  • Start een interactieve shell opnieuw om een bewerkte module opnieuw te testen.

1.4 Installeer pakketten voor de Python die je uitvoert

Pakketten van derden voegen code toe die niet met Python wordt meegeleverd. PyPI, de Python Package Index op https://pypi.org, biedt onderdak aan deze projecten. pip downloadt en installeert ze voor een specifieke Pythoninstallatie.

Gebruik eerst de terminal en daarna Python

Een terminalopdracht en een Pythoninstructie horen op verschillende plaatsen thuis. De prompt >>> betekent dat je in de interactieve shell van Python zit. Als je daar pip install requests invoert, krijg je SyntaxError; Python kan dit niet als instructie lezen.

Voer in je terminal uit:

python -m pip install cowsay

Zet dit vervolgens in een Pythonprogramma:

import cowsay

cowsay.cow("Hello, Ada")

Het programma drukt een koe van teksttekens af naast een tekstballon met het bericht. De installatie maakt het pakket beschikbaar; de import maakt de binding ervoor aan in het programma.

Stem pip af op je interpreter

Met de vorm -m pip vraag je de genoemde Python om zijn eigen pip uit te voeren. Gebruik de opdracht waarmee je je programma’s start: vaak python3 op macOS of Linux, of py op Windows.

python3 -m pip install cowsay
python3 game.py

Beide regels kiezen dezelfde Pythonopdracht. Als een installatie meldt dat die is geslaagd, maar een script nog steeds ModuleNotFoundError opwerpt, vergelijk dan de Python waarmee is geïnstalleerd met die waarmee het script wordt uitgevoerd. Een editor kan een andere interpreter hebben geselecteerd dan je terminal. Gebruik de pip van de geselecteerde interpreter voordat je de import wijzigt.

Bekijk en onderhoud een installatie
TerminalopdrachtTaak
python -m pip listGeïnstalleerde pakketten en versies weergeven
python -m pip show requestsDetails tonen, waaronder de installatielocatie
python -m pip install --upgrade requestsBijwerken naar de nieuwste beschikbare versie
python -m pip install "requests==2.32.3"Precies die versie selecteren
python -m pip uninstall requestsHet pakket verwijderen

Een exacte versie is nuttig als je het gedrag van die specifieke uitgave nodig hebt. Met show kun je controleren welke locatie pip daadwerkelijk heeft gewijzigd.

Controleer de naam in de documentatie

De distributienaam die je voor pip typt kan verschillen van de importnaam. Installeer beautifulsoup4 en gebruik daarna import bs4; installeer Pillow en gebruik daarna import PIL. De importnaam herhaaldelijk installeren is geen nuttige oplossing wanneer de documentatie een andere distributie noemt.

De standaardbibliotheek van Python, inclusief math, random en unittest, wordt al met Python meegeleverd. Deze modules vereisen geen installatie met pip.

Houd rekening met een beheerde installatie

Sommige besturingssystemen en pakketbeheerders beschermen hun Python met een foutmelding externally-managed-environment. Dit betekent dat een directe installatie wordt geblokkeerd om de beheerde installatie consistent te houden. Gebruik een virtuele omgeving, een afzonderlijke map met Python en pakketten voor het project. Forceer de installatie niet met sudo pip install.

Iedereen kan op PyPI publiceren. Controleer vóór de installatie de exacte spelling en lees de pagina en documentatie van het project. Namen die erop lijken kunnen pogingen tot typosquatting zijn. Geef de voorkeur aan gevestigde, onderhouden pakketten en installeer de pakketten die je programma echt nodig heeft.

Belangrijkste punten

  • Voer pip-opdrachten uit in een terminal en imports in Pythoncode.
  • Gebruik python -m pip met dezelfde interpreteropdracht als waarmee je het programma uitvoert.
  • Controleer de importnaam in de documentatie; die kan verschillen van de installatienaam.
  • Gebruik pip om een pakket te bekijken, bij te werken, een versie te kiezen of het pakket te verwijderen.
  • Een beheerde Python kan een virtuele omgeving voor het project vereisen.
  • Controleer de spelling en documentatie van een pakket voordat je code van derden installeert.
2

Lees foutmeldingen en stacktraces

De foutuitvoer van Python legt zowel de mislukte bewerking vast als de aanroepen die daartoe leidden. Door die aanwijzingen op volgorde te lezen, vind je gemakkelijker een bruikbaar startpunt dan wanneer je de eerste regel wijzigt die je herkent. Je volgt een stacktrace terug naar de invoer, maakt onderscheid tussen veelvoorkomende exceptietypen en herkent het minder opvallende geval waarin een programma normaal draait maar het verkeerde resultaat geeft. Het verwachte gedrag geeft je iets concreets om te controleren.

2.1 Volg een stacktrace terug naar de verkeerde invoer

Een stacktrace vertelt welke aanroepen actief waren toen een niet-afgehandelde exceptie het programma stopte. Hij geeft zowel een startpunt om te lezen als een weg terug naar de waarde die de fout veroorzaakte.

Begin bij de laatste regel

Bekijk dit volledige programma in scores.py:

def average(values):
    return sum(values) / len(values)

def report(scores):
    avg = average(scores)
    print(f"Average: {avg:.1f}")

report([])

De laatste regel van het foutverslag is ZeroDivisionError: division by zero. Die noemt het exceptietype en beschrijft de mislukte bewerking. Begin daar en lees dan omhoog naar de codelocatie direct erboven.

Een vereenvoudigde stacktrace, zonder expressiemarkeringen, is:

Traceback (most recent call last):
  File "scores.py", line 8, in <module>
    report([])
  File "scores.py", line 5, in report
    avg = average(scores)
  File "scores.py", line 2, in average
    return sum(values) / len(values)
ZeroDivisionError: division by zero
Lees elk frame als een actieve aanroep

Een aanroepframe geeft het bestand, het regelnummer en de functie, gevolgd door de bijbehorende code. in <module> betekent code op moduleniveau. De oudste aanroep staat bovenaan; de meest recente staat onderaan. Als je van onderen leest, keer je die volgorde om zodat je kunt vragen wat er misging voordat je vraagt hoe de uitvoering daar terechtkwam.

  1. Regel 2 deelt door len(values). Wil die deler nul zijn, dan moet values leeg zijn.
  2. Regel 5 roept average(scores) aan, dus onderzoek de scores die report doorgaf.
  3. Regel 8 geeft [] door, de lege lijst. Dat verklaart hoe de deler nul in de berekening terechtkwam.

De regel waar de fout optreedt en de oorzaak hangen samen, maar kunnen op verschillende plaatsen staan. Als je de deling vervangt zonder te bepalen wat een lege lijst moet betekenen, verberg je de ontwerpvraag. Ofwel moet de aanroepende code een lege lijst vermijden, ofwel moet voor de functie zijn vastgelegd wat ze bij lege invoer doet.

Gebruik markeringen zonder afhankelijk te zijn van hun exacte vorm

Python 3.11 en later kunnen de markeringen ^ en ~ toevoegen om het deel van een expressie te tonen waar de fout optreedt. Ze helpen wanneer één regel meerdere bewerkingen bevat. De precieze markering verschilt per versie, maar de aanroeplocaties en exceptiemelding geven nog steeds de leesvolgorde aan.

Een stacktrace kan frames uit de standaardbibliotheek of een geïnstalleerd pakket bevatten. Zoek het onderste frame in je eigen code en onderzoek de argumenten die je daar doorgaf. Een bibliotheekframe is een aanwijzing voor de locatie; het is geen bewijs dat de bibliotheek de programmeerfout bevat.

Herken een syntaxisfoutmelding

Een syntaxisfout in het script dat wordt gestart, verhindert dat script te draaien. Python meldt een bestand, regel, markering en melding zonder de gebruikelijke kop van een stacktrace. Zo ontbreekt bij if True de dubbele punt; bij total = sum([1, 2, 3] blijft een haakje open.

De gemarkeerde plaats is waar Python merkte dat het de code niet kon ontleden. Als die regel geldig lijkt, controleer dan de vorige regel op een niet-gesloten aanhalingsteken of haakje. Er is geen keten van aanroepen tijdens de uitvoering om te volgen wanneer het startscript niet is uitgevoerd.

Een gewone uitvoering stopt bij de eerste niet-afgehandelde exceptie. Herstel dat probleem en voer het programma opnieuw uit om eventuele latere problemen zichtbaar te maken.

Belangrijkste punten

  • Lees eerst het exceptietype en de melding, daarna het frame waar de fout optrad en de aanroepende code.
  • Frames lopen van de oudste actieve aanroep bovenaan tot de nieuwste onderaan.
  • Volg de verkeerde waarde terug; de bron kan vóór het vastlopen liggen.
  • Een syntaxisfout in het startscript wordt gemeld voordat dat script wordt uitgevoerd.

2.2 Maak onderscheid tussen een verkeerde naam, type, waarde en uitkomst

De naam van een fout bakent de zoektocht af en de melding geeft meer details over de betrokken waarden. Een programma kan ook onjuist zijn zonder een exceptie op te werpen, dus de verwachte uitvoer controleren blijft onderdeel van het zoeken naar fouten.

Maak onderscheid tussen drie soorten problemen
SoortWat gebeurt erVoorbeeld
SyntaxisfoutPython kan de code niet ontledenEen ontbrekende dubbele punt na if
UitvoeringsfoutDe uitvoering bereikt een ongeldige bewerkingDelen door nul
Logische foutDe uitvoering eindigt met verkeerd gedragEen lus slaat een prijs over

IndentationError is een soort SyntaxError. Functie-inhoud moet zijn ingesprongen; een ontbrekend ingesprongen blok stopt de code voordat die wordt uitgevoerd. Controleer ook op niet-gesloten aanhalingstekens of haakjes en verkeerd gespelde gereserveerde woorden.

Lees namen en typen zorgvuldig

Een NameError betekent dat het programma op dat punt een naam niet kent. In prnt("hi") is de bedoelde ingebouwde functie print. Een naam kan ook vóór de toekenning zijn gebruikt, of een import kan ontbreken.

Een TypeError betekent dat een bewerking een ongeschikt type kreeg of een aanroep het verkeerde aantal argumenten kreeg. "Age: " + 30 mengt een string en een geheel getal. Schrijf "Age: " + str(30) of f"Age: {30}". Als area de parameters w en h nodig heeft, is area(3) ook een TypeError, ditmaal vanwege een ontbrekend argument.

De melding maakt onderscheid tussen deze oorzaken. In can only concatenate str (not "int") to str noemt Python de typen die bij elkaar kwamen. Na age = input("Age: ") is age tekst. age + 1 mislukt; bij invoer van een geheel getal voert int(age) + 1 een berekening uit.

Een ValueError betekent dat het type van de invoer wordt geaccepteerd, maar de waarde ongeschikt is. int("12.5") krijgt een string, een geaccepteerd invoertype, maar de tekst stelt geen geheel getal in de vereiste vorm voor. math.sqrt(-1) is nog een ongeschikte waarde voor een berekening met reële getallen.

Controleer posities, sleutels en attributen
ExceptieVoorbeeldOorzaak
IndexError[4, 6, 10][3]De laatste geldige index is 2
KeyError{"apples": 3}["pears"]De dictionary bevat "pears" niet
ZeroDivisionError10 / 0De deler is nul
AttributeErrormath.sqroot(16)De module bevat sqroot niet
ModuleNotFoundErrorimport mathhEr is geen module onder die naam gevonden
ImportErrorfrom math import square_rootDe module bevat die geïmporteerde naam niet

Delen door nul mislukt ook met // en %. Een ontbrekende lijstpositie opzoeken is iets anders dan een ontbrekende dictionarysleutel opzoeken, ook al vraag je in beide gevallen om iets wat ontbreekt.

Ontdek een resultaat dat aannemelijk lijkt
def total_price(prices):
    total = 0
    for i in range(1, len(prices)):
        total += prices[i]
    return total

Voor [4, 6, 10] geeft dit 16 terug in plaats van 20. Er is geen exceptie: de indexen 1 en 2 bestaan, dus elke bewerking is toegestaan. De lus begint te laat en slaat index 0 over. De fout wordt zichtbaar wanneer je de uitvoer vergelijkt met het bedoelde totaal.

Zoek bij een onbekende exceptie het type en de algemene melding op in de officiële Pythondocumentatie. Laat je eigen paden en invoerwaarden weg uit een zoekopdracht; die verklaren zelden de algemene regel.

Belangrijkste punten

  • Syntaxisfouten verhinderen het ontleden; uitvoeringsfouten ontstaan tijdens de uitvoering; logische fouten geven verkeerd gedrag.
  • NameError gaat over een binding; TypeError gaat over een type of aanroepargumenten.
  • ValueError gaat over een ongeschikte waarde van een geaccepteerd type.
  • IndexError, KeyError en AttributeError verwijzen naar verschillende soorten opzoekingen.
  • Door uitvoer te vergelijken met een verwacht resultaat kun je een logische fout zonder stacktrace ontdekken.
3

Vind de oorzaak van een programmeerfout

Een verkeerd resultaat is gemakkelijker te onderzoeken als je het kunt reproduceren en precies kunt zeggen hoe het verschilt van het verwachte resultaat. Je zet die waarneming om in een toetsbaar vermoeden, bakent de zoektocht af tot een klein stuk code en onderzoekt de waarden die ertoe doen. Uitvoerinstructies, uitvoeringstabellen en debuggeropdrachten bieden verschillende manieren om de uitvoering te volgen. Na een gerichte reparatie helpt het controleren van eerder werkende gevallen om te ontdekken welk gedrag door de wijziging is beïnvloed.

3.1 Toets een oorzaak voordat je de code wijzigt

Een programmeerfout is een verschil tussen bedoeld en werkelijk gedrag. Bij het debuggen zoek en herstel je de oorzaak. Tijdens een zinvolle debugsessie zet je een waarneming om in een toetsbare verklaring en wijzig je de code op basis van bewijs.

Zorg dat de fout zich herhaalt

Leg specifieke invoer en het resultaat dat die oplevert vast. Gebruik voor de prijsfunctie die haar lus bij index 1 begint [4, 6, 10]. Het verwachte totaal is 20; het werkelijke totaal is 16. Met deze concrete waarden kun je controleren of elk onderzoek nog steeds over dezelfde programmeerfout gaat.

Het verschil is 4 en het werkelijke resultaat is gelijk aan 6 + 10. Een specifieke hypothese is dat de eerste prijs wordt overgeslagen. Die hypothese voorspelt iets wat je kunt onderzoeken: de lus zal index 0 nooit bezoeken.

Volg zes stappen
  1. Reproduceer: zoek invoer die de programmeerfout steeds laat zien.
  2. Vermeld het verwachte en werkelijke resultaat: bereken het verwachte resultaat onafhankelijk.
  3. Vorm een hypothese: noem een mogelijke oorzaak en het voorspelde gedrag.
  4. Toets de hypothese: onderzoek waarden met uitvoerinstructies, een uitvoeringstabel of een debugger.
  5. Herstel de oorzaak: maak één gerichte wijziging.
  6. Test opnieuw: voer de invoer waarbij het misging en eerder werkende gevallen uit.

Druk de index binnen de lus af. Voor deze invoer zijn de enige indexen 1 en 2, wat de voorspelling bevestigt. Als je range bij 0 laat beginnen, herstel je het overgeslagen element. Door direct over de prijzen te itereren hoef je geen index meer bij te houden:

def total_price(prices):
    total = 0
    for price in prices:
        total += price
    return total

De herstelde functie geeft 20 terug voor [4, 6, 10], 5 voor [5] en 0 voor []. Het geval met één element is nuttig omdat de foutieve lus daarvoor eerder 0 teruggaf.

Als je 4 bij elk antwoord optelt, herstel je het waargenomen totaal maar blijft de oorzaak bestaan. Voor [5] zou die noodoplossing 4 teruggeven; het ontbrekende bedrag hangt af van de invoer. Controleer of een voorgestelde oplossing al het bewijs verklaart voordat je die behoudt.

Baken een grotere zoektocht af

Bij verdeel en heers controleer je op een punt tijdens de uitvoering de waarden die bijdragen aan het verkeerde resultaat. Als een benodigde waarde al verkeerd is, onderzoek je de eerdere code die haar produceerde. Als de benodigde waarden nog juist zijn, volg je hoe ze later worden verwerkt. Herhaal dit binnen het overgebleven gedeelte.

Je kunt ook één functie afzonderlijk aanroepen of niet-gerelateerde code tijdelijk verwijderen. Een minimaal reproduceerbaar voorbeeld behoudt de kortste code en kleinste invoer waarbij het nog steeds misgaat. Bij een probleem dat je eerst in honderden records zag, maakt het vinden van één of twee records die het veroorzaken elk onderzoek gemakkelijker.

Controleer wat de gegevens werkelijk zijn

Een weergegeven 5 kan de string "5" zijn. "5" + "3" levert "53" op, terwijl optellen met getallen 8 geeft. Onderzoek type(value) om het type te controleren. Gebruik repr(value) om spaties en regeleindetekens zichtbaar te maken die een gewone print-instructie kan verbergen, zoals in ' Ada'.

Leg de code hardop uit, regel voor regel, inclusief wat elke lus daadwerkelijk doorloopt en wat elke functie teruggeeft. Dit is debuggen met een badeendje: door een stap uit te leggen ontdek je vaak het verschil tussen de bedoelde en de geschreven bewerking.

Wijzig één oorzaak tegelijk zodat je het resultaat aan de aanpassing kunt koppelen. Test zowel de gevallen die eerder werkten als het geval waarin het misging opnieuw.

Belangrijkste punten

  • Reproduceer de programmeerfout en leg het verwachte en werkelijke resultaat vast voordat je iets wijzigt.
  • Een bruikbare hypothese voorspelt iets wat je kunt onderzoeken.
  • Herstel de oorzaak met één wijziging en test daarna opnieuw de mislukte en eerder werkende gevallen.
  • Gebruik een minimaal voorbeeld of tussenwaarden om de zoektocht af te bakenen.
  • Controleer typen en verborgen tekens wanneer waarden misleidend lijken.

3.2 Bekijk hoe waarden veranderen met uitvoerinstructies en een debugger

Het eindantwoord van een programma verbergt de weg waarlangs het is ontstaan. Met tijdelijke uitvoerinstructies, een uitvoeringstabel en een debugger kun je die weg bekijken en een specifieke hypothese toetsen over waar het misgaat.

Druk een waarde op een bekend moment af

Voorzie diagnostische uitvoer van een label zodat de betekenis van een getal duidelijk is. Python 3.8 en later ondersteunen deze f-stringvorm:

print(f"{i=} {total=}")

Zet die voor de foutieve prijslus direct vóór total += prices[i]. Met prijzen [4, 6, 10] wordt afgedrukt:

i=1 total=0
i=2 total=6

Dit zijn totalen vóór elke optelling. Na de eerste uitvoerinstructie telt de lus 6 op; na de tweede telt ze 10 op. Een uitvoerinstructie na de optelling zou andere totalen tonen. Bepaal welk moment je vraag beantwoordt voordat je de uitvoer interpreteert.

Volg dezelfde code met de hand

Een uitvoeringstabel legt variabelen stap voor stap vast. Voor deze lus:

Index iOpgetelde prijsTotaal ervoorTotaal erna
1606
210616

Er is geen iteratie voor index 0. Volg de werkelijke startwaarde en eindgrens die in de code staan, ook als je al weet wat de lus zou moeten doen. Een tabel helpt onderscheiden wat je verwacht van wat er gebeurt.

Pauzeer bij een onderbrekingspunt

Een debugger pauzeert een draaiend programma zodat je de huidige toestand kunt onderzoeken. Een onderbrekingspunt markeert een plaats om te pauzeren. Klik in editors zoals Thonny en VS Code naast een regelnummer en start de debugmodus; klik in IDLE met de rechtermuisknop op de regel en kies Set Breakpoint.

Kies na het pauzeren een stap op basis van de vraag die je onderzoekt:

OpdrachtEffect
Regel uitvoeren zonder functies binnen te gaanVoer de huidige regel uit, inclusief een aangeroepen functie
Functie binnengaanGa een functie binnen die op die regel wordt aangeroepen
Functie verlatenVoltooi deze functie en pauzeer na de terugkeer
DoorgaanVoer uit tot een volgend onderbrekingspunt of het programma eindigt

Als de aanroepende code correcte argumenten doorgeeft maar een verkeerd antwoord ontvangt, ga dan de functie binnen. Als je alleen het teruggegeven resultaat hoeft te zien, voer de aanroep dan uit zonder de functie binnen te gaan. Onderzoek de waarden vóór en na de regel die de fout kan veroorzaken.

Gebruik de tekstdebugger van Python

Voeg breakpoint() in direct vóór de code die je wilt onderzoeken. Bij de standaardconfiguratie van de debugger start het programma op dat punt pdb. Typ deze opdrachten bij de prompt (Pdb):

  • p total toont total.
  • n voert de volgende regel uit zonder functies binnen te gaan.
  • s gaat een functieaanroep binnen.
  • c gaat verder met de uitvoering.
  • q beëindigt de debugsessie.

Dit zijn debuggeropdrachten, geen regels om naar je programma te kopiëren.

Maak onderscheid tussen afgedrukte uitvoer en retourwaarden

Een functie kan het juiste getal afdrukken en toch None teruggeven omdat return total ontbreekt. Onderzoek de waarde die de aanroepende code ontvangt wanneer de fout na de functieaanroep optreedt. Correcte uitvoer binnen de functie bewijst niet dat de aanroepende code dat getal heeft ontvangen.

Gebruik uitvoerinstructies voor snel bewijs over lusiteraties en de debugger om een bepaald moment te onderzoeken. Verwijder na het herstellen van de programmeerfout tijdelijke uitvoerinstructies en breakpoint()-aanroepen zodat het voltooide programma normaal draait.

Belangrijkste punten

  • Voorzie uitvoerinstructies voor debuggen van labels en let erop of ze vóór of na een bijwerking worden uitgevoerd.
  • Een uitvoeringstabel volgt werkelijke variabelewijzigingen stap voor stap.
  • Onderbrekingspunten pauzeren de uitvoering; stapopdrachten bepalen hoeveel code daarna wordt uitgevoerd.
  • breakpoint() opent standaard pdb; p, n, s, c en q zijn debuggeropdrachten.
  • Onderzoek retourwaarden wanneer een functie correct afdrukt maar de aanroepende code faalt.
  • Verwijder tijdelijke diagnostische uitvoer en onderbrekingspunten na de reparatie.
4

Controleer je functies met tests

Met geautomatiseerde controles kun je een nuttig voorbeeld telkens herhalen wanneer een functie verandert. Je schrijft asserties met duidelijke verwachtingen, kiest invoer op de grenzen van een regel en voorkomt dat tests de toepassing starten die ze importeren. Het standaardtestraamwerk unittest geeft elke test vervolgens een naam en een afzonderlijk resultaat. Het lezen van mislukte tests en testfouten verbindt testen met debuggen: de test reproduceert een probleem en onderzoek vindt de oorzaak.

4.1 Schrijf controles die mislukken als een aanname onwaar is

Een assertie legt vast wat waar moet zijn als je code correct werkt. Ze kan een programmeerfout stoppen dicht bij de plaats waar die ontstaat of het resultaat van een functie vergelijken met de waarde die je verwacht.

Schrijf een voorwaarde en een optionele melding
assert letter_grade(90) == "A", "90 should be an A"

Python evalueert de voorwaarde. Als letter_grade(90) de waarde "A" teruggeeft, is de voorwaarde waar en gaat de uitvoering verder zonder uitvoer. Als de functie "B" teruggeeft, werpt Python AssertionError op met de melding 90 should be an A. De stacktrace wijst naar de mislukte controle.

Zonder de melding controleert assert letter_grade(90) == "A" nog steeds het resultaat. De laatste exceptieregel bevat AssertionError, terwijl de stacktrace de expressie toont. Een nuttige melding noemt de verwachting waaraan niet is voldaan; ze moet je helpen de regel te vinden die wordt gecontroleerd.

Stop een interne fout vroegtijdig

Stel dat een interne berekening een niet-lege lijst vereist:

def average(values):
    assert len(values) > 0, "values must not be empty"
    return sum(values) / len(values)

Een lege lijst activeert nu de assertie vóór de deling. De controle documenteert de interne aanname van de functie en wijst direct aan wanneer daaraan niet is voldaan. Ze geeft een lege lijst geen gemiddelde en bepaalt niet hoe een toepassing moet reageren op ontbrekende gegevens van een gebruiker.

Houd gebruikersvalidatie actief

De optie -O van Python verwijdert assert-instructies. Een programma dat op een assertie vertrouwt om invoer van buitenaf af te wijzen, kan zich daardoor anders gedragen wanneer het is geoptimaliseerd. Controleer gebruikersinvoer en andere gegevens van buitenaf met gewone programmasturing:

def require_score(score):
    if score < 0 or score > 100:
        raise ValueError("score must be 0 to 100")
    return score

Hier meldt raise ValueError(...) een ongeschikte waarde. De if-instructie wordt ook onder -O uitgevoerd. Kies een assertie voor een interne programmeeraanname en een actieve invoercontrole voor gegevens die van buitenaf onjuist kunnen worden aangeleverd.

Vermijd een controle die nooit kan mislukken

assert is een instructie, geen functie. Schrijf de voorwaarde en de melding met een komma ertussen:

assert x > 10, "x too small"

Als je assert (x > 10, "x too small") schrijft, maak je een tuple met twee elementen. Een niet-lege tuple is waar, ook als het eerste element False is, dus de assertie slaagt. Python kan waarschuwen dat deze assertie altijd waar is. Haakjes rond alleen een voorwaarde, zoals in assert (x > 10), maken die tuple niet aan; de komma binnen de haakjes is het probleem.

Gebruik == om te vergelijken. assert total = 20 is ongeldige syntaxis omdat = een waarde toekent.

Vergelijk getallen met de bedoelde precisie

Gebruik voor een berekend zwevendekommagetal een controle op benaderende gelijkheid:

import math

assert math.isclose(0.1 + 0.2, 0.3)

Een exacte vergelijking mislukt hier omdat de opgeslagen som als zwevendekommagetal iets afwijkt van 0.3. Een eenvoudige geautomatiseerde test past hetzelfde idee van een assertie toe op een functie: assert total_price([4, 6, 10]) == 20. De verwachte waarde komt uit de regel van de functie, zodat de controle een verkeerde implementatie kan blootleggen.

Belangrijkste punten

  • assert condition, message werpt AssertionError op als de voorwaarde onwaar is.
  • Asserties kunnen interne aannames en verwachte functieresultaten controleren.
  • Gebruik if en een foutmelding of exceptie voor invoer van buitenaf; -O verwijdert asserties.
  • Een komma binnen assert (condition, message) maakt een als waar beschouwde tuple.
  • Gebruik == voor gelijkheid en math.isclose voor vergelijkingen van berekende zwevendekommagetallen.

4.2 Kies tests die een programmeerfout kunnen blootleggen

Een unittest controleert een klein onderdeel van de code, meestal één functie, met gekozen invoer en een verwacht resultaat. Geautomatiseerde tests maken het gemakkelijk om dezelfde controles na wijzigingen te herhalen en helpen zo fouten op te sporen die terugkeren in eerder werkend gedrag.

Begin bij de specificatie

Stel dat een beoordelingsfunctie "A" moet teruggeven voor scores van minstens 90, "B" voor scores van minstens 80 maar lager dan 90, en "C" onder 80. De foutieve eerste voorwaarde is score > 90.

Tests moeten verschillende taken vervullen:

  • Typische gevallen controleren gewone invoer binnen elk gebied, zoals 95 en 85.
  • Grensgevallen controleren de waarden waar een regel verandert, zoals 90 en 89, of 80 en 79.
  • Randgevallen controleren invoer zoals nul of een lege collectie wanneer de regels van de functie die toestaan.

Leid het verwachte antwoord af uit die regels. Als je het antwoord van het huidige programma naar een test kopieert, kun je de fout ervan behouden.

Zet de tests naast de module

Sla tests op in test_grade.py en de functie in grade.py. De start van de toepassing in grade.py hoort onder de __main__-voorwaarde, zodat het importeren van de functie het programma niet start.

from grade import letter_grade

def test_letter_grade():
    assert letter_grade(95) == "A"
    assert letter_grade(90) == "A"
    assert letter_grade(85) == "B"

Bij de foutieve regel slaagt de eerste assertie. De tweede mislukt omdat 90 niet groter is dan 90; de uitvoering stopt daar, vóór de derde assertie in deze functie. Door de eerste voorwaarde te veranderen in score >= 90 herstel je deze grens. Voer alle tests opnieuw uit om het betreffende geval en het eerdere gedrag te controleren.

Zorg dat de tests daadwerkelijk worden uitgevoerd

Een testfunctie definiëren roept haar niet aan. Voeg zonder testuitvoerder test_letter_grade() onderaan het testbestand toe en voer daarna python test_grade.py uit. Om pytest te gebruiken, installeer je het met python -m pip install pytest en voer je daarna pytest test_grade.py uit in de terminal. Het vindt de testfuncties en meldt hun resultaten. Laat handmatige aanroepen weg als een testuitvoerder ze beheert.

Een test die alleen letter_grade(90) aanroept, bevat geen vergelijking. Die kan succesvol eindigen terwijl het teruggegeven antwoord verkeerd is; de test mislukt alleen als de aanroep een onverwachte exceptie opwerpt. Een assertie verbindt de aanroep met het vereiste gedrag.

Test retourwaarden en eigenschappen van willekeurige resultaten

Een functie die alleen een totaal afdrukt, geeft None terug. Een vergelijking zoals assert print_total([4, 6]) == 10 mislukt daarom ook als het scherm 10 toont. Laat de berekening haar antwoord teruggeven en laat main het afdrukken verzorgen.

Willekeurige resultaten vereisen een andere verwachting. Van een dobbelsteenfunctie zonder ingestelde startwaarde kun je niet eisen dat die bij elke aanroep precies dezelfde uitkomst teruggeeft. Controleer of elk van 100 aanroepen een toegestane waarde van 1 tot en met 6 teruggeeft, of stel een startwaarde in voor een herhaalbare reeks. Een geslaagde grenscontrole controleert de grenzen voor die aanroepen; ze bewijst niet dat elke uitkomst even waarschijnlijk is.

Als een nieuwe programmeerfout verschijnt, voeg dan vóór de reparatie een test toe die daardoor mislukt. Bewaar die regressietest zodat latere wijzigingen hetzelfde gedrag opnieuw controleren. Geslaagde tests leggen vast wat er in de geteste gevallen gebeurde; met meer invoer kun je nog een andere fout ontdekken.

Belangrijkste punten

  • Leid verwachte resultaten onafhankelijk van de implementatie af uit de specificatie.
  • Test gewone invoer, grenzen van regels en relevante randgevallen.
  • Testfuncties hebben een aanroep of een testuitvoerder nodig; definities alleen voeren geen controles uit.
  • Asserties moeten retourwaarden vergelijken met het bedoelde gedrag.
  • Test passende eigenschappen van willekeurige uitvoer of zorg voor een herhaalbare reeks.
  • Bewaar voor elke nieuw gevonden programmeerfout een test om regressies op te sporen.

4.3 Voer een unittest-testbestand uit en interpreteer het

Python bevat unittest, een testraamwerk dat tests opspoort, uitvoert en afzonderlijke resultaten meldt. Installatie met pip is niet nodig. Je kunt de klassenstructuur als sjabloon gebruiken terwijl je functies leert testen.

Schrijf onafhankelijke testmethoden

Zet dit voor een functie in grade.py in test_grade.py:

import unittest
from grade import letter_grade

class TestLetterGrade(unittest.TestCase):
    def test_top(self):
        self.assertEqual(letter_grade(95), "A")

    def test_boundary(self):
        self.assertEqual(letter_grade(90), "A")

    def test_low(self):
        self.assertEqual(letter_grade(50), "C")

if __name__ == "__main__":
    unittest.main()

TestLetterGrade erft de testhulpmiddelen over van unittest.TestCase. Elke test is een methode waarvan de naam met test begint. self verwijst naar het huidige testobject; behoud dit in de parameterlijst van elke methode en vóór aanroepen van assertiemethoden. Je kunt deze structuur kopiëren zonder zelf klassen te ontwerpen.

Tests worden standaard alfabetisch op methodenaam uitgevoerd, dus test_boundary komt vóór test_low en test_top. Laat elke test de eigen benodigde invoer aanleveren en onafhankelijk van eerdere tests werken.

Kies een assertiemethode
MethodeControle
self.assertEqual(actual, expected)Waarden zijn gelijk
self.assertNotEqual(a, b)Waarden verschillen
self.assertTrue(condition)Een voorwaarde is waar
self.assertFalse(condition)Een voorwaarde is onwaar
self.assertIn(item, collection)Het element behoort tot de collectie
self.assertAlmostEqual(a, b)Het verschil wordt standaard op 7 decimalen afgerond nul

Geef bij het vergelijken van waarden de voorkeur aan assertEqual(a, b) boven assertTrue(a == b): het verslag van de mislukte test toont de twee waarden. De unittest-methoden behouden hun controles ook wanneer Python onder -O draait.

Om een verwachte exceptie te controleren, plaats je de aanroep binnen assertRaises:

def test_score_too_high(self):
    with self.assertRaises(ValueError):
        letter_grade(120)

Deze test vereist dat de regel van de functie die score afwijst met ValueError. Als de functie terugkeert zonder exceptie, mislukt deze controle; een andere exceptie dan een assertie is een testfout.

Voer uit en lees het verslag

Voer python test_grade.py uit om de door de voorwaarde beschermde unittest.main() uit te voeren. Of voer python -m unittest uit om test*.py-bestanden in de huidige map op te sporen. python -m unittest -v drukt afzonderlijke testnamen en hun resultaten af.

In het korte verslag betekent . geslaagd, F dat een assertie is mislukt en E dat een andere exceptie is opgetreden. Voor een beoordelingsfunctie met score > 90 leveren de drie bovenstaande tests F.. op. Het verslag van de mislukte test test_boundary toont 'B' != 'A': het werkelijke resultaat is "B", terwijl het verwachte resultaat "A" is. De samenvatting vermeldt drie tests en één mislukte test.

Controleer de verwachting van de test aan de hand van de beoordelingsregels voordat je de functie wijzigt. Een verkeerde verwachting vereist een aanpassing van de test. Als er geen tests worden uitgevoerd, controleer dan de methodenamen, de voorwaarde voor directe uitvoering en de startopdracht. Noem je bestand ook geen unittest.py, want dat verbergt de standaardmodule.

Belangrijkste punten

  • Zet test-methoden in een klasse die overerft van unittest.TestCase.
  • Gebruik self.assertEqual en andere assertiemethoden voor duidelijke controles en verslagen.
  • assertRaises controleert een verwachte exceptie; voor vergelijkingen van zwevendekommagetallen kun je assertAlmostEqual gebruiken.
  • Voer een testbestand met een voorwaarde voor directe uitvoering rechtstreeks uit of gebruik python -m unittest om tests op te sporen.
  • Lees F als een mislukte assertie en E als een andere exceptie.
  • Controleer een mislukte test aan de hand van de specificatie voordat je de functie wijzigt.
  • Elke test moet onafhankelijk van de alfabetische uitvoeringsvolgorde werken.

Modules en debuggen in Python: voorbeelden

4 Walkthroughs

1

Bouw een programma uit herbruikbare onderdelen

20 stappen
Kies imports en bibliotheekfuncties, hergebruik je eigen code en koppel geïnstalleerde pakketten aan de Python die ze uitvoert.
  1. 1
    IntroductieBegin met code die je kunt hergebruiken

    Een programma kan code aanroepen uit de standaardbibliotheek van Python, uit een ander bestand dat je hebt geschreven of uit een geïnstalleerd pakket. De eerste vraag is welke naam het programma na het importeren beschikbaar heeft.

    Je volgt een berekening van een import tot de retourwaarde, richt daarna een herbruikbare module in en koppelt een pakketinstallatie aan de bijbehorende interpreter. Controleer onderweg of een resultaat een waarde is die je bewaart of een wijziging aan een bestaande lijst.

  2. 2
    UitlegDe import bepaalt de aanroepstijl

    Deze imports maken dezelfde functie via verschillende bindingen beschikbaar:

    import math
    print(math.sqrt(16))
    
    from math import sqrt
    print(sqrt(16))
    

    Beide drukken 4.0 af. De eerste maakt math aan, dus de aanroep gebruikt een punt. De tweede maakt sqrt aan en heeft dus geen modulevoorvoegsel nodig. De verkeerde aanroepstijl werpt NameError op wanneer die naam niet is gebonden.

  3. 3
    VoorbeeldBereken de schuine zijde

    Met import math kun je voor een rechthoekige driehoek met zijden 3 en 4 gebruiken:

    length = math.sqrt(3**2 + 4**2)
    

    De kwadraten zijn 9 en 16. Hun som is 25 en math.sqrt(25) geeft 5.0 terug. Python evalueert het argument voordat de functie wordt aangeroepen.

    Het voorvoegsel vertelt een lezer ook waar sqrt vandaan komt. Een import met een jokerteken verbergt die herkomst en kan bestaande namen vervangen, zoals een variabele met de naam e.

  4. 4
    UitdagingVolg de aliasbinding

    Een nieuw script voert deze regels uit. Wat gebeurt er op de laatste regel en hoe kun je dat herstellen?

    import statistics as st
    print(statistics.mean([4, 8, 12]))
    

    ---reveal---

    Het werpt NameError op omdat de import st bindt, niet statistics. Gebruik st.mean([4, 8, 12]), dat 8 teruggeeft. Een alias kiest de binding in dit programma; hij maakt niet ook de oorspronkelijke modulenaam aan.

  5. 5
    VoorbeeldRond af voor voldoende hele verpakkingen

    Voor een muur is verf nodig voor 23 vierkante meter. Elk blik dekt 10 vierkante meter.

    import math
    cans = math.ceil(23 / 10)
    

    De deling geeft 2.3; ceil geeft 3, genoeg hele blikken. round(2.3) geeft slechts 2.

    Voor negatieve invoer betekent naar beneden nog steeds in de richting van min oneindig: math.floor(-2.5) is -3, terwijl int(-2.5) afkapt in de richting van nul en -2 geeft.

  6. 6
    KernpuntStem de vergelijking af op het getal

    Berekende zwevendekommagetallen kunnen iets afwijken van de bedoelde waarden die er decimaal uitzien:

    0.1 + 0.2 == 0.3               # False
    math.isclose(0.1 + 0.2, 0.3)   # True
    

    Gebruik voor die benaderende vergelijking een controle op nabijheid. Daarnaast blijft de toegestane invoer van een functie van belang: math.sqrt(-1) werpt ValueError op.

    De ingebouwde functie round hoef je niet te importeren. Bij een waarde precies halverwege kiest ze het naastgelegen even getal: round(2.5) is 2 en round(3.5) is 4.

  7. 7
    UitlegKies het willekeurige resultaat dat je nodig hebt

    Kies na import random een aanroep op basis van de taak:

    • randint(1, 6) kiest een geheel getal inclusief 6.
    • randrange(1, 6) kiest een geheel getal exclusief 6.
    • random() geeft een zwevendekommagetal van 0,0 tot, maar exclusief, 1,0.
    • choice(items) kiest één element.
    • sample(items, k) kiest k posities zonder terugleggen.

    Twee geselecteerde posities kunnen dezelfde waarde bevatten. Als je in [1, 1] beide posities trekt, krijg je daarom herhaaldelijk de waarde 1.

  8. 8
    UitdagingBehoud de geschudde lijst

    Welke waarde bevat names aan het eind en hoe moet de laatste regel veranderen om de lijst te behouden?

    names = ["Mina", "Luis", "Jo"]
    names = random.shuffle(names)
    

    ---reveal---

    De waarde is None. shuffle verandert de bestaande lijst en geeft daarna None terug; de toekenning vervangt de binding met de lijst door die retourwaarde. Gebruik random.shuffle(names) op een eigen regel. De nieuwe volgorde van de lijst is willekeurig, maar de retourwaarde staat vast.

  9. 9
    VerbandHerhaal een simulatie en vind andere hulpmiddelen

    Roep random.seed(42) aan voordat je waarden genereert om dezelfde reeks op dezelfde Pythonversie te herhalen. Daardoor is een willekeurig optredende fout gemakkelijker te reproduceren. Gebruik secrets voor beveiligingstokens.

    Andere standaardmodules lossen alledaagse taken op: statistics.mean([2, 4, 9]) geeft 5 en median geeft 4. datetime.date.today() geeft de datum van vandaag. sys.argv bevat de naam van het uitgevoerde script gevolgd door de opdrachtregelargumenten.

  10. 10
    VoorbeeldZet een herbruikbare functie in een module

    Sla dit op als geometry.py:

    import math
    
    def circle_area(radius):
        """Return the circle's area."""
        return math.pi * radius ** 2
    

    Een script in dezelfde map kan import geometry uitvoeren en daarna print(geometry.circle_area(2)). Het drukt 12.566370614359172 af.

    Importeer het bestand zonder .py. De eerste string van de functie is haar docstring, die help(geometry.circle_area) kan tonen.

  11. 11
    UitlegEen import voert instructies op moduleniveau uit

    Stel dat geometry.py eindigt met print(circle_area(2)), buiten een functie. De eerste import drukt als neveneffect de oppervlakte af.

    Python voert instructies op moduleniveau op volgorde uit. Door circle_area te definiëren maak je de functie aan zonder haar inhoud uit te voeren; als je haar aanroept binnen de print-instructie op moduleniveau, wordt de berekening uitgevoerd. Een tweede import in hetzelfde proces hergebruikt de geladen module. Ook een interactieve shell behoudt die geladen versie nadat het bestand is bewerkt, totdat je de shell opnieuw start.

  12. 12
    VoorbeeldStart alleen bij directe uitvoering

    Laat de herbruikbare functie boven dit blok staan:

    def main():
        print(circle_area(2))
    
    if __name__ == "__main__":
        main()
    

    Bij directe uitvoering krijgt __name__ de waarde "__main__", zodat main() wordt uitgevoerd. Bij een import krijgt die de waarde "geometry", zodat de start wordt overgeslagen.

    De definities blijven in beide gevallen beschikbaar. Zo kan een test circle_area importeren zonder de gewone uitvoer van het programma te produceren.

  13. 13
    UitdagingHoud de functie beschikbaar voor wie importeert

    Een bestand definieert convert binnen zijn if __name__ == "__main__":-blok. Een nieuw testproces importeert het bestand en kan convert niet vinden. Welke indeling maakt zowel hergebruik als de start bij directe uitvoering mogelijk?

    ---reveal---

    Verplaats def convert(...) buiten de voorwaarde en laat alleen de start van het programma daarbinnen staan. Tijdens de import is de voorwaarde onwaar, dus wordt een definitie daarbinnen overgeslagen. Door de definitie te verplaatsen maak je haar beschikbaar zonder de toepassing te starten.

  14. 14
    TipControleer het bestand dat een import vindt

    Python controleert ingebouwde modules en doorzoekt daarna sys.path op volgorde. De map van het script staat normaal gesproken vóór bibliotheekmappen. Een lokaal random.py kan daardoor de random verbergen die je wilde importeren.

    Geef dat bestand een andere naam, zoals dice.py. Gebruik voor je eigen hulpfuncties geldige namen zoals my_tools.py en bewaar ze naast het beginnersscript dat ze importeert. Een bestand buiten het zoekpad wordt met een gewone import niet gevonden.

  15. 15
    VoorbeeldInstalleer in de terminal, importeer in Python

    Voer in de terminal uit:

    python -m pip install cowsay
    

    Daarna kan Pythoncode dit gebruiken:

    import cowsay
    cowsay.cow("Hello, Ada")
    

    Het pakket drukt een koe van teksttekens en een tekstballon af. pip installeert code, terwijl import de binding aanmaakt die je programma gebruikt. De installatieopdracht is geen Pythoninstructie; bij een prompt >>> levert ze ongeldige syntaxis op.

  16. 16
    UitlegGebruik de pip die hoort bij de uitgevoerde Python

    Als een script met python3 wordt uitgevoerd, installeer dan via dezelfde opdracht:

    python3 -m pip install cowsay
    python3 game.py
    

    -m pip selecteert de pip die bij die interpreter hoort. Op Windows kan je opdracht in plaats daarvan py zijn.

    Als de editor een succesvol geïnstalleerd pakket niet kan importeren, vergelijk dan de geselecteerde interpreter met de interpreter die in de terminal is gebruikt. Een geslaagde installatie in één Python installeert het pakket niet in elke andere Python.

  17. 17
    UitdagingMaak onderscheid tussen de installatie- en importnaam

    De documentatie van een pakket zegt dat je Pillow moet installeren en PIL moet importeren. De installatie slaagt voor de Python die je uitvoert, maar import Pillow mislukt. Wat moet veranderen en waarom?

    ---reveal---

    Gebruik import PIL. De distributienaam die pip gebruikt kan verschillen van de Pythonimportnaam die het pakket levert. Omdat al is vastgesteld dat de interpreter overeenkomt, zou het herhalen van dezelfde installatieopdracht deze specifieke naamfout niet oplossen.

  18. 18
    TipBekijk een pakket voordat je het wijzigt

    python -m pip list toont geïnstalleerde versies. show requests geeft de versie en locatie van één pakket; install --upgrade requests werkt het bij en uninstall requests verwijdert het. Elke korte opdracht volgt op python -m pip.

    Controleer vóór installatie de exacte PyPI-naam en de projectdocumentatie. Gebruik bij een fout externally-managed-environment een virtuele omgeving voor het project; forceer een installatie niet met sudo pip install.

  19. 19
    UitdagingVoorspel een import en een latere aanroep

    Een nieuwe module sizes.py bevat deze code. Een ander script voert from sizes import batches uit en daarna print(batches(17)). Wat wordt afgedrukt?

    import math
    
    def batches(n):
        return math.ceil(n / 5)
    
    if __name__ == "__main__":
        print(batches(12))
    

    ---reveal---

    Alleen 4 wordt afgedrukt. De import maakt de functie aan maar slaat de print-instructie onder de voorwaarde over. De latere aanroep deelt 17 door 5 en rondt daarna 3,4 naar boven af op 4. De binding math binnen sizes is beschikbaar voor de functie.

  20. 20
    SamenvattingVolg code van de bron tot de aanroep

    Kies een import die past bij de namen die je wilt gebruiken. Controleer wat een bibliotheekaanroep teruggeeft, waaronder een mogelijke None van een bewerking die een lijst verandert.

    Houd herbruikbare definities beschikbaar tijdens het importeren en plaats de start van de toepassing achter de voorwaarde voor directe uitvoering. Stem voor geïnstalleerde code pip af op de gebruikte interpreter en controleer de gedocumenteerde importnaam. Als een aanroep mislukt, helpen deze details onderscheid te maken tussen een ontbrekende binding, een ontbrekend attribuut en een ontbrekende installatie.

2

Volg een fout terug naar de oorzaak

11 stappen
Lees aanroepframes, herken veelvoorkomende excepties en maak onderscheid tussen vastlopen en een verkeerd resultaat zonder foutmelding.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieGebruik het verslag als bewijs
  2. 2
    VoorbeeldEen lege lijst bereikt een deling
  3. 3
    UitlegZoek het meest recente frame
  4. 4
    VoorbeeldVolg het argument terug via de aanroepende code
  5. 5
    UitdagingZoek een ongeschikt argument
  6. 6
    UitlegMaak onderscheid tussen grammatica, typen en waarden
  7. 7
    UitlegVerschillende opzoekingen geven verschillende fouten
  8. 8
    VoorbeeldEen programma kan normaal eindigen met een verkeerd totaal
  9. 9
    UitdagingVerklaar een mislukte optelling
  10. 10
    UitdagingGebruik een bibliotheekframe zonder de bibliotheek de schuld te geven
  11. 11
    SamenvattingKies waar je verder zoekt
3

Onderzoek een programmeerfout van bewijs tot reparatie

14 stappen
Reproduceer een verkeerd totaal, onderzoek de lus, maak een gerichte reparatie en gebruik debuggeropdrachten om een functieaanroep te volgen.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieZorg dat het verkeerde resultaat zich herhaalt
  2. 2
    VoorbeeldVermeld het verwachte en werkelijke resultaat
  3. 3
    UitlegMaak het vermoeden toetsbaar
  4. 4
    VoorbeeldDruk af vóór de bijwerking
  5. 5
    VoorbeeldVolg de optellingen met de hand
  6. 6
    UitdagingInterpreteer uitvoer na de bijwerking
  7. 7
    VoorbeeldHerstel de iteratie zelf
  8. 8
    VerbandTest invoer met verschillende vormen opnieuw
  9. 9
    TipVerklein een groter probleem
  10. 10
    UitdagingControleer een waarde die op een getal lijkt
  11. 11
    UitlegPauzeer bij de aanroep die je wilt onderzoeken
  12. 12
    UitdagingKies de stapopdracht
  13. 13
    UitdagingOnderzoek correcte uitvoer en een verkeerde retourwaarde
  14. 14
    SamenvattingBlijf de reparatie koppelen aan bewijs
4

Maak van een grensfout een blijvende test

16 stappen
Schrijf asserties, kies invoer die fouten blootlegt en gebruik unittest om onafhankelijke controles uit te voeren en de resultaten te interpreteren.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieGeef verwacht gedrag een herhaalbare controle
  2. 2
    UitlegEen assertie legt een verwachting vast
  3. 3
    UitdagingZoek een controle die niet kan mislukken
  4. 4
    KernpuntHoud controles op invoer van buitenaf actief
  5. 5
    VoorbeeldKies invoer rond de beoordelingsgrens
  6. 6
    VoorbeeldSchrijf een testfunctie die de code importeert
  7. 7
    TipVoer de controles uit die je hebt gedefinieerd
  8. 8
    UitdagingHerstel een drempelwaarde en bewaar de controle
  9. 9
    VerbandTest het teruggegeven resultaat of een geldige eigenschap
  10. 10
    VoorbeeldGebruik het klassensjabloon van unittest
  11. 11
    UitlegKies de assertie voor het resultaat
  12. 12
    VoorbeeldLees een mislukte beoordelingscontrole
  13. 13
    UitdagingMaak onderscheid tussen een mislukte test en een testfout
  14. 14
    TipControleer wat het opsporen daadwerkelijk heeft uitgevoerd
  15. 15
    UitdagingGebruik een verslag om de reparatie te plannen
  16. 16
    SamenvattingBewaar een test voor het gedrag dat je hebt hersteld

Modules en debuggen in Python: oefenvragen

40 Oefenvragen in 4 sets

Set 1: Volg oorzaken door modules en tests10 Oefenvragen

Vraag 1 van 10

Wat drukt deze code af?

from math import sqrt as root
sqrt = 4
result = root(sqrt ** 2)
print(result, sqrt)
  1. 16.0 4
  2. 4.0 4.0
  3. De code werpt TypeError op omdat sqrt een geheel getal is.
  4. 4.0 4
Toon antwoordVerberg antwoord
Antwoord: D
De import bindt de functie aan root, dus de toekenning van 4 aan sqrt vervangt die functiebinding niet. De aanroep neemt de vierkantswortel van 16 en geeft 4.0 terug, terwijl sqrt gelijk blijft aan 4. Een aanroep van sqrt(...) zou hier mislukken, maar deze code roept root(...) aan.

Vraag 2 van 10

Een trekking gebruikt random.sample(["blue", "blue", "red"], 2). Waarom kan het resultaat twee waarden "blue" bevatten?
  1. Trekken legt het eerste element altijd terug vóór de volgende trekking.
  2. De twee blauwe waarden staan op verschillende invoerposities.
  3. De waarde 2 vraagt twee identieke kopieën van een gekozen element.
  4. Trekken verwijdert dubbele waarden pas nadat ze zijn teruggegeven.
Toon antwoordVerberg antwoord
Antwoord: B
sample selecteert invoerposities zonder terugleggen en de lijst heeft twee posities met "blue". Als beide worden geselecteerd, kunnen dus herhaalde waarden ontstaan zonder dezelfde positie twee keer te kiezen. Zonder terugleggen verwijst naar posities; het maakt dubbele invoerwaarden niet verschillend.

Vraag 3 van 10

Een module bevat deze code. Een nieuw proces importeert de module en roept daarna helper.answer() aan. Wat gebeurt er?

# helper.py
if __name__ == "__main__":
    def answer():
        return 42
  1. De aanroep geeft 42 terug omdat Python eerst alle definities laadt.
  2. NameError: Python definieert __name__ nooit tijdens een import.
  3. AttributeError: bij de import is de functiedefinitie overgeslagen.
  4. De aanroep geeft None terug omdat de voorwaarde retourwaarden verandert.
Toon antwoordVerberg antwoord
Antwoord: C
Bij de import krijgt __name__ de waarde "helper", dus wordt het blok onder de voorwaarde overgeslagen. Omdat de definitie zelf binnen dat blok staat, heeft de module geen attribuut answer. Houd herbruikbare definities buiten de voorwaarde en plaats alleen de programmastart eronder; Python verzamelt overgeslagen definities niet vooraf.

Vraag 4 van 10

Een stacktrace begint met je aanroep van run_report(), daarna je aanroep van parse(raw), en eindigt binnen een bibliotheekconversie met ValueError. Je onderzoekt raw bij je aanroep van parse en vindt "9x", hoewel de regel tekst in de vorm van een geheel getal vereist. Waar moet het onderzoek nu naartoe?
  1. Volg terug waar raw de waarde "9x" kreeg vóór de aanroep van parse.
  2. Vervang int(raw) door int(raw[0]) zodat deze invoer een getal oplevert.
  3. Beschouw het bibliotheekframe als bewijs van een fout en wijzig de conversie.
  4. Laat de invoer staan en installeer de bibliotheek opnieuw omdat de aanroep al liep.
Toon antwoordVerberg antwoord
Antwoord: A
Het bibliotheekframe toont waar de conversie een ongeschikte waarde detecteerde, terwijl het onderzochte argument verklaart waarom die mislukte. Volg de eerdere code die "9x" doorgaf en vergelijk die met de regel voor gehele getallen. De locatie van een bibliotheekframe bewijst op zichzelf niet dat de conversie van de bibliotheek verkeerd is.

Vraag 5 van 10

Een functie drukt 18 af maar heeft geen return-instructie. De aanroepende code evalueert daarna result + 2, waarbij result de retourwaarde van de aanroep is. Waarom ontstaat een TypeError?
  1. result is None, wat niet bij 2 kan worden opgeteld.
  2. result is de string "18" omdat afdrukken retourwaarden omzet.
  3. result is 18, maar twee gehele getallen optellen is hier ongeldig.
  4. result is ongedefinieerd omdat elke print-instructie de binding verwijdert.
Toon antwoordVerberg antwoord
Antwoord: A
Een functie die haar einde bereikt zonder een waarde terug te geven, geeft None terug, ook als ze een getal heeft afgedrukt. De aanroepende code probeert daardoor None + 2, wat TypeError opwerpt. Afdrukken toont tekst; het maakt het afgedrukte getal niet tot het resultaat dat de functie teruggeeft.

Vraag 6 van 10

Een verwerkingsketen leest, converteert en totaliseert gegevens. Bij een herhaalbare fout zijn de waarden voor het totaal direct na de conversie al verkeerd. Alleen het lezen levert de verwachte ruwe waarden op. Wat is het meest gerichte vervolgonderzoek?
  1. Voeg een correctie toe aan het eindtotaal en laat de conversie ongewijzigd.
  2. Herschrijf alle drie de stappen samen en vergelijk alleen de einduitvoer.
  3. Voer alleen de conversie uit op de kleinste ruwe invoer waarbij het misgaat.
  4. Onderzoek alleen de laatste uitvoerinstructie omdat daar de verkeerde uitvoer verschijnt.
Toon antwoordVerberg antwoord
Antwoord: C
De onderzochte waarden beperken de fout tot de conversiestap: het lezen is correct en het latere totaal ontvangt al verkeerde gegevens. Isoleer de conversie met de kleinste invoer waarbij de fout blijft optreden en onderzoek daarna de stappen. Het eindtotaal oplappen laat de waargenomen verkeerde conversie onverklaard en kan andere invoer verstoren.

Vraag 7 van 10

Een debugger is gepauzeerd op answer = calculate(7). Je wilt de eerste regel binnen calculate onderzoeken. Welke opdracht gebruik je?
  1. Regel uitvoeren zonder functies binnen te gaan
  2. Functie binnengaan
  3. Functie verlaten
  4. Doorgaan
Toon antwoordVerberg antwoord
Antwoord: B
Met functie binnengaan ga je de functie binnen die op de huidige regel wordt aangeroepen, zodat je de interne uitvoering kunt onderzoeken. De regel uitvoeren zonder functies binnen te gaan zou de aanroep als één stap uitvoeren en na voltooiing pauzeren. Daarmee kun je de retourwaarde onderzoeken, maar sla je de interne regel over die je wilt bekijken.

Vraag 8 van 10

De regel zegt dat een rit gratis is voor afstanden tot en met 6 en 3 kost boven 6. charge(6) geeft 3 terug, maar de test verwacht 3 en slaagt. Welke wijziging maakt een nuttige regressietest en herstelt de regel?
  1. Behoud 3 bij 6 en voeg alleen een test toe voor een verre betaalde rit.
  2. Verander de regel zodat 6 betaald is en behoud de bestaande test.
  3. Verwijder de controle bij 6 en vergelijk alleen twee geslaagde voorbeelden.
  4. Verwacht 0 bij 6, zie de test mislukken, herstel en test opnieuw.
Toon antwoordVerberg antwoord
Antwoord: D
Volgens de specificatie is 6 gratis, dus de huidige verwachte waarde van de test neemt de programmeerfout over. Door de verwachting eerst te corrigeren naar 0 maak je een controle die voor de werkelijke regel mislukt. Door daarna de implementatie te wijzigen en de testverzameling opnieuw uit te voeren controleer je de reparatie; de verkeerde verwachting behouden zou de fout blijven goedkeuren.

Vraag 9 van 10

Een unittest-bestand bevat test_alpha, dat 4 verwacht maar 5 ontvangt, een geslaagde test_beta en test_gamma, dat onverwacht TypeError opwerpt. Welke compacte voortgangsstring levert de standaard alfabetische uitvoering op?
  1. E.F
  2. F.E
  3. F.F
  4. .FE
Toon antwoordVerberg antwoord
Antwoord: B
test_alpha wordt eerst uitgevoerd en registreert een mislukte assertie, F. test_beta slaagt, wat . geeft, en test_gamma registreert een testfout, E, omdat die een andere exceptie opwerpt. Als je het laatste resultaat als nog een F behandelt, verdwijnt het onderscheid tussen een onware assertie en een onverwachte exceptie.

Vraag 10 van 10

Een unittest.TestCase heeft check_empty met een mislukte gelijkheidscontrole en test_full met een geslaagde controle. De testuitvoerder meldt één test en OK. Hoe zorg je dat de ontbrekende gedragscontrole wordt uitgevoerd?
  1. Hernoem check_empty naar test_empty en voer opnieuw uit.
  2. Voeg return False toe aan het einde van check_empty.
  3. Verplaats check_empty onder test_full in de klasse.
  4. Vervang assertEqual door print in check_empty.
Toon antwoordVerberg antwoord
Antwoord: A
Unittest spoort methoden op via hun voorvoegsel test, dus is check_empty overgeslagen en verklaart de ene geslaagde methode het verslag. Door haar te hernoemen wordt de ontbrekende controle bij de volgende uitvoering zichtbaar. De methode verplaatsen verandert haar positie in het bestand, maar niet of ze bij het opsporen wordt herkend.
Set 2: Combineer keuzes over importeren, debuggen en testen10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Een simulatie stelt één keer een startwaarde in en roept daarna random.randint(2, 5) 50 keer aan. Een nieuwe test stelt dezelfde startwaarde in op dezelfde Pythonversie en herhaalt dezelfde aanroepen. Wat moeten de controles verwachten?
  1. De reeks herhaalt zich en elk resultaat ligt van 2 tot en met 5.
  2. De reeks herhaalt zich en elk resultaat ligt van 2 tot en met 4.
  3. Elk resultaat komt even vaak voor en alle vier waarden verschijnen.
  4. Elke aanroep geeft weer het eerste resultaat omdat de startwaarde blijft staan.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

De documentatie noemt beautifulsoup4 als distributie en bs4 als module ervan. Een script importeert bs4 met succes. Een collega wil python -m pip install beautifulsoup4 veranderen om bs4 te installeren zodat de namen overeenkomen. Is het overeenkomen van die namen een goede reden voor die wijziging?
  1. Ja; elke geslaagde import moet de installatienaam van de distributie gebruiken.
  2. Ja; het importeren van bs4 bewijst dat pip een distributie onder die naam installeerde.
  3. Nee; de installatie volgt de gedocumenteerde distributienaam, die kan verschillen.
  4. Nee; de module moet eerst worden hernoemd naar de huidige distributienaam.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een nieuwe uitvoering van display.py meldt deze aanroepen van boven naar beneden: start(" "), read_count(text) en daarna int(text), eindigend met ValueError. Welke volgorde toetst de waarschijnlijke oorzaak het best vóór een reparatie?
  1. Onderzoek alleen type(text); een string ontvangen bewijst een typefout.
  2. Onderzoek repr(text), bevestig de lege invoer en bepaal daarna het invoergedrag.
  3. Verplaats dezelfde conversie naar start zodat die vóór de andere functieaanroepen draait.
  4. Vervang elke mislukte conversie door nul zonder het vereiste invoergedrag te controleren.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een totaalfunctie slaat het eerste element over. Een noodoplossing telt 6 op bij elk teruggegeven totaal en slaagt nu voor [6, 3, 2]. Welke verwachte en werkelijke resultaten voor twee nieuwe invoerwaarden leggen het resterende probleem bloot?
  1. [9]: verwacht 9, werkelijk 15; []: verwacht 0, werkelijk 6.
  2. [9]: verwacht 9, werkelijk 6; []: verwacht 0, werkelijk 0.
  3. [9]: verwacht 6, werkelijk 6; []: verwacht 6, werkelijk 6.
  4. [9]: verwacht 9, werkelijk 6; []: verwacht 0, werkelijk 6.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Deze functie drukt een correct product af, maar de aanroepende code krijgt een TypeError in area(4, 5) + 1. Waar moet je onderzoeken en welk resultaat verklaart de fout?

def area(w, h):
    product = w * h
    print(product)
  1. Voer de aanroep uit zonder de functie binnen te gaan; de retourwaarde is het gehele getal 20.
  2. Voer de aanroep uit zonder de functie binnen te gaan; de retourwaarde is de string "20".
  3. Voer de aanroep uit zonder de functie binnen te gaan; de retourwaarde is None.
  4. Ga de functie binnen; het afgedrukte resultaat wordt de retourwaarde.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Wat gebeurt er bij een gewone, niet-geoptimaliseerde uitvoering?

import math
assert math.isclose(0.1 + 0.2, 0.3)
assert 0.1 + 0.2 == 0.3
  1. De eerste assertie slaagt; de tweede werpt AssertionError op.
  2. Beide asserties slagen omdat decimale sommen exact worden opgeslagen.
  3. De eerste assertie mislukt; de tweede wordt nooit uitgevoerd.
  4. Beide asserties mislukken maar het programma gaat door tot het einde.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

pick() geeft een willekeurig geheel getal van 3 tot en met 7 terug, inclusief beide grenzen. pair_total() telt de resultaten van twee aanroepen van pick() op. Een test die stelt dat elk totaal zonder ingestelde startwaarde gelijk is aan 10, mislukt soms terwijl beide functies correct werken. Welke controle per resultaat past bij het vereiste bereik van de totalen?
  1. Controleer met een assertie 3 <= value <= 7 voor elk totaal.
  2. Controleer met een assertie 6 <= value < 14 voor elk totaal.
  3. Controleer met een assertie value == 10 voor elk totaal.
  4. Controleer met een assertie 6 <= value <= 14 voor elk totaal.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

reserve(n) moet gehele aantallen van 0 tot en met 8 accepteren en buiten dat bereik ValueError opwerpen. Tests met assertRaises(ValueError) melden F voor -1 omdat er geen exceptie optreedt, en E voor 9 omdat een TypeError optreedt. Een test met 2 slaagt. Welk gedrag moet de reparatie opleveren?
  1. Accepteer -1 normaal; werp ValueError op bij 9; houd 2 geldig.
  2. Werp ValueError op bij -1 en 9; houd 2 geldig.
  3. Werp ValueError op bij -1; behoud TypeError bij 9; houd 2 geldig.
  4. Accepteer -1 en 9 normaal; werp ValueError op bij 2.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een script heet random.py en importeert random, maar loopt daarna vast omdat random.randint ontbreekt. Welke eerste wijziging pakt het naamconflict aan?
  1. Installeer de module random opnieuw met pip.
  2. Verplaats import random onder de aanroep van randint.
  3. Behoud random.py en gebruik from random import randint.
  4. Hernoem het script naar draw_numbers.py.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Een programma heeft assert total == 10 voor een interne berekening en assert age >= 0 voor gebruikersinvoer. Het wordt uitgevoerd onder -O met total gelijk aan 9 en age gelijk aan -1. Wat gebeurt er met die controles en welke wijziging behoudt de vereiste invoervalidatie?
  1. Alleen de totaalcontrole verdwijnt; geef de leeftijdsassertie een langere melding.
  2. Beide controles verdwijnen; zet de leeftijdsvoorwaarde en melding in een tuple.
  3. Beide controles verdwijnen; gebruik if age < 0 en een foutreactie voor de invoer.
  4. Alleen de leeftijdscontrole verdwijnt; verplaats die naar een functie test_age.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 3: Modules, keuzes bij debuggen en testresultaten10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Na import statistics as st is de volgende regel statistics.mean([3, 7]). Er zijn geen andere imports of toekenningen. Wat verklaart de fout?
  1. De functie mean vereist ook import math.
  2. Alleen st is gebonden; roep st.mean([3, 7]) aan.
  3. Alleen mean is gebonden; roep mean([3, 7]) aan.
  4. De alias moet worden doorgegeven als statistics.mean(st).
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Wat is de waarde van tickets na deze code?

import random
tickets = [11, 22, 33]
tickets = random.shuffle(tickets)
  1. Een opnieuw geschudde lijst met drie elementen
  2. Het eerste element van de geschudde lijst
  3. De oorspronkelijke lijst in de oorspronkelijke volgorde
  4. None
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een hulpmodule definieert double en bevat daarna de onbeschermde regel print(double(6)). Een ander script importeert de module twee keer tijdens één uitvoering. Hoe vaak drukt die regel iets af?
  1. Eén keer, tijdens de eerste import
  2. Twee keer, één keer per import-instructie
  3. Nooit, omdat imports alleen functienamen lezen
  4. Eén keer, alleen als het script later double aanroept
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een editor voert een script uit met Python A. De terminalopdracht python -m pip show cowsay meldt een locatie in Python B en de editor kan cowsay niet importeren. Wat moet je eerst doen?
  1. Voer de pip-installatie van Python B opnieuw ongewijzigd uit.
  2. Vervang de import door het mappad van het pakket.
  3. Voer -m pip install cowsay uit met Python A.
  4. Verplaats het script naar de bibliotheekmap van Python B.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een stacktrace heeft drie frames. Waar vind je het exceptietype en de melding als eerste?
  1. In het eerste frame, bij de scriptnaam
  2. In de kop boven het eerste frame
  3. Op de regel met de oudste aanroep
  4. Op de laatste regel, onder de frames
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Deze functie moet elke hoeveelheid optellen. Welk soort probleem verklaart het resultaat van total([2, 5, 8])?

def total(values):
    result = 0
    for i in range(1, len(values)):
        result += values[i]
    return result
  1. Er ontstaat een IndexError omdat de lus index 3 bereikt.
  2. Een logische fout geeft 13 terug omdat index 0 wordt overgeslagen.
  3. Er ontstaat een TypeError omdat lijstelementen niet kunnen worden opgeteld.
  4. Er ontstaat een syntaxisfout omdat range drie argumenten nodig heeft.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een gegevensverwerkend programma dat niet goed werkt heeft 300 regels en 200 records. Wat maakt een nuttig minimaal reproduceerbaar voorbeeld?
  1. De volledige code met elk record en alle diagnostische uitvoer
  2. Het verwachte antwoord zonder de invoer waarbij het misgaat
  3. De kortste code en kleinste invoer waarbij het nog misgaat
  4. Een herschreven programma waarvan de uitvoer al is hersteld
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een invoercontrole gebruikt assert (score >= 0, "negative score"). Die slaagt wanneer score gelijk is aan -3. Welke wijziging herstelt de controle en houdt de validatie actief onder -O?
  1. if score < 0: raise ValueError("negative score")
  2. assert score >= 0, "negative score"
  3. assert (score < 0, "negative score")
  4. assert (score >= 0) == True
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een gewoon testbestand definieert test_discount, met twee asserties, maar roept de functie nooit aan. Je voert dat bestand uit met python test_discount.py; er is geen code van een testuitvoerder. Waarom worden geen asserties gecontroleerd?
  1. Python verwijdert elke assertie uit elk test_-bestand.
  2. Elke assertie moet boven de functie worden geplaatst.
  3. Het definiëren van de functie voert haar inhoud niet uit.
  4. De testfunctie moet vóór de aanroep True teruggeven.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Een unittest-methode roept self.assertEqual(lookup("x"), 7) aan. De aanroep van lookup werpt onverwacht KeyError op voordat hij terugkeert. Welk kort resultaat markeert deze test?
  1. F, omdat elk probleem in een test een mislukte assertie is
  2. E, omdat een andere exceptie de controle onderbrak
  3. ., omdat geen gelijkheidsvergelijking onwaar teruggaf
  4. F, omdat KeyError hetzelfde is als AssertionError
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Set 4: Imports, foutaanwijzingen en eerste controles10 Oefenvragen

Sla deze les op om elk antwoord te zien en elke set te oefenen.

Vraag 1 van 10

Een script bevat vóór de berekening alleen import math. Hoe moet het de vierkantswortelfunctie aanroepen voor 81?
  1. sqrt(81)
  2. math(81).sqrt()
  3. math.sqrt(81)
  4. import.sqrt(81)
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

In een pendelbus passen 8 mensen. Wat geeft math.ceil(35 / 8) terug en wat stelt dit voor?
  1. 5, de benodigde pendelbussen voor iedereen
  2. 4, de benodigde pendelbussen voor iedereen
  3. 4.375, de pendelbussen die je moet boeken
  4. 4, het aantal zitplaatsen dat leeg blijft
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een bestand met de naam text_tools.py definieert shorten. Hoe kan een ander bestand in dezelfde map die functie importeren en aanroepen?
  1. import text_tools.py, daarna text_tools.shorten("Hello")
  2. import shorten, daarna shorten.text_tools("Hello")
  3. import text_tools, daarna shorten.text_tools("Hello")
  4. import text_tools, daarna text_tools.shorten("Hello")
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Je staat bij een Pythonprompt >>> en voert pip install cowsay in. Waarom meldt Python ongeldige syntaxis?
  1. Het pakket moet worden geïmporteerd voordat het kan worden geïnstalleerd.
  2. De installatieopdracht moet in de terminal worden uitgevoerd.
  3. De pakketnaam moet met de uitgang .py worden geschreven.
  4. De installatieopdracht heeft een Pythontoekenning nodig.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een stacktrace eindigt met ZeroDivisionError. De frames tonen van boven naar beneden show([]), mean(data) en sum(values) / len(values). Welke keten verklaart de fout het best?
  1. De functie show probeerde haar eigen naam door nul te delen.
  2. Een lege lijst bereikte mean, waardoor de deler nul werd.
  3. De lijst werd leeg omdat de stacktrace achteruit afdrukt.
  4. De som was nul, waardoor delen altijd ongeldig wordt.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Welke exceptie werpt int("7.25") op?
  1. TypeError
  2. NameError
  3. IndexError
  4. ValueError
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een functie moet [9, 2, 5] optellen tot 16 maar geeft 7 terug. Je vermoedt dat ze het eerste element overslaat. Welke waarneming toetst dat idee het meest direct?
  1. Leg de indexen vast die de optellus bezoekt.
  2. Druk het verwachte totaal na de functieaanroep opnieuw af.
  3. Tel 9 op bij het resultaat en controleer alleen dezelfde invoer.
  4. Hernoem de totaalvariabele en voer opnieuw uit zonder onderzoek.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Welke twee regels worden afgedrukt?

total = 0
for n in [3, 8]:
    print(f"{n=} {total=}")
    total += n
  1. n=3 total=3, daarna n=8 total=11
  2. n=3 total=0, daarna n=8 total=0
  3. n=3 total=0, daarna n=8 total=3
  4. n=0 total=3, daarna n=3 total=8
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Wat gebeurt er als deze code normaal wordt uitgevoerd?

count = 6
assert count < 5, "too many"
print("saved")
  1. De code werpt AssertionError op met "too many".
  2. De code drukt "saved" af en meldt daarna de assertie.
  3. De code kent 5 toe aan count en gaat door zonder uitvoer.
  4. De code drukt "too many" af en daarna "saved".
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

De regel is: gratis tot en met gewicht 12, een vergoeding van 4 voor 13 tot en met 18 en een vergoeding van 7 boven 18. Tests voor 5 en 20 slagen. Welke resultaten en wijziging geven een juiste diagnose van deze code?

def fee(weight):
    if weight < 12:
        return 0
    if weight <= 18:
        return 4
    return 7
  1. Bij 12: 0; bij 18: 7. Verander de tweede voorwaarde in < 18.
  2. Bij 12: 4; bij 18: 7. Verander beide vergelijkingen in <.
  3. Bij 12: 0; bij 18: 4. Laat beide vergelijkingen ongewijzigd.
  4. Bij 12: 4; bij 18: 4. Verander de eerste voorwaarde in <= 12.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Kom je niet uit je eigen opgave? Huiswerkhulp

Kernbegrippen

60 Kernbegrippen, elk met een definitie

A

aanroepframe
Een aanroepframe in een stacktrace duidt de locatie van een actieve aanroep aan met het bestand, regelnummer en de functie, samen met de relevante bronregel.
Het onderste frame kan een deling door de lengte van een lege lijst tonen, terwijl eerdere frames onthullen welke aanroeper die lijst doorgaf.
aanroepketen
Een aanroepketen is de reeks actieve functieaanroepen die tot de huidige bewerking leidde, van de buitenste aanroepende code tot de meest recente aanroep.
Een aanroepketen van een report-functie naar een average-functie laat zien hoe een lijst de functie bereikte die door de lengte ervan deelde.
alias
Een alias is de naam die je met as kiest voor een geïmporteerde module of een geïmporteerd object; de import bindt die naam in het importerende programma.
Met de alias stats in import statistics as stats kan het script stats.mean([1, 3, 8]) aanroepen.
assertie
Een assertie controleert een voorwaarde die waar moet zijn als de code correct is, gaat verder als die waar is en werpt AssertionError op als die onwaar is.
Een assertie zoals assert count == 3 vergelijkt een intern resultaat met het aantal dat je onafhankelijk verwacht.
AssertionError
Een AssertionError signaleert een mislukte assertie en kan een opgegeven melding bevatten die uitlegt aan welke verwachting de controle niet voldeed.
Een AssertionError met "wrong total" vestigt de aandacht op de test die het berekende totaal vergeleek.
automatisch opsporen van tests
Automatisch opsporen van tests vindt uitvoerbare tests met regels voor bestands- en methodenamen, zoals het standaardbestandspatroon test*.py van unittest.
Door tests automatisch op te sporen met python -m unittest kun je passende bestanden uitvoeren zonder ze elk in een opdracht te noemen.

B

bewerking ter plaatse (in-place operation)
Een bewerking ter plaatse verandert een bestaand object, zoals een lijst, zonder dat een nieuw object nodig is om de gewijzigde inhoud te bevatten.
De bewerking ter plaatse random.shuffle(cards) verandert cards en geeft None terug, dus is geen toekenning nodig.

C

code op moduleniveau
Code op moduleniveau bestaat uit instructies op moduleniveau, buiten functies, die op volgorde worden uitgevoerd wanneer een module voor het eerst wordt geladen.
Code op moduleniveau die print aanroept, kan tijdens een import uitvoer produceren, ook wanneer de importerende code geen functie aanroept.

D

debuggen
Debuggen is het proces van onverwacht gedrag reproduceren, de oorzaak vinden, die herstellen en het betreffende gedrag opnieuw controleren.
Bij het debuggen van een lus die prijzen optelt bekijk je de indexen die de lus bezoekt voordat je de startwaarde van de lus wijzigt.
debuggen met uitvoerinstructies
Bij debuggen met uitvoerinstructies voeg je tijdelijke uitvoer toe op gekozen plaatsen in de code om waarden, uitvoeringsvolgorde en de overeenkomst tussen een hypothese en het gedrag zichtbaar te maken.
Bij debuggen met uitvoerinstructies voorziet print(f"{i=} {total=}") de lusindex en het totaal op het onderzochte moment van labels.
debugger
Een debugger pauzeert de uitvoering van een programma en biedt opdrachten om huidige waarden te onderzoeken en stap voor stap door de code te gaan.
Met een debugger kun je calculate binnengaan om de argumenten te onderzoeken wanneer de aanroepende code een verkeerd antwoord ontvangt.
distributie
Een distributie is een installeerbaar Pythonproject dat wordt aangeduid met een naam voor de pakketbeheerder, die kan verschillen van de naam die bij imports wordt gebruikt.
De distributie beautifulsoup4 wordt onder die naam geïnstalleerd, maar de documentatie zegt dat Pythongebruikers bs4 moeten importeren.
docstring
Een docstring is een string aan het begin van een module of functie die het doel documenteert en via help() kan worden getoond.
Een docstring bij circle_area kan het straalargument uitleggen en de oppervlakte die aan de aanroepende code wordt teruggegeven.

E

exceptie
Een exceptie signaleert een probleem dat tijdens de uitvoering is gedetecteerd; een niet-afgehandelde exceptie stopt het programma en produceert normaal gesproken een stacktrace.
Een exceptie door deling door nul kan average stoppen voordat de aanroepende code het berekende gemiddelde afdrukt.

F

functie binnengaan (step into)
Functie binnengaan is een debuggeractie die een functie binnengaat die op de huidige regel wordt aangeroepen, zodat je de stappen binnen die functie kunt onderzoeken.
Gebruik functie binnengaan bij result = convert(text) wanneer de retourwaarde verkeerd is en de invoertekst correct lijkt.

G

grensgeval
Een grensgeval is testinvoer op een grens waar een regel verandert, waardoor fouten met inclusieve en exclusieve vergelijkingen gemakkelijker te ontdekken zijn.
Een grensgeval met score 90 controleert of de regel voor beoordeling A de vereiste inclusieve vergelijking gebruikt.

H

hypothese
Een hypothese is een specifiek voorgestelde verklaring voor een programmeerfout die een waarneming voorspelt die je in het draaiende programma kunt controleren.
De hypothese dat een lus haar eerste element overslaat, voorspelt dat uitvoer van de indexen nooit 0 toont.

I

import met een jokerteken
Een import met een jokerteken gebruikt * om de openbare namen van een module naar het huidige programma te halen, wat de herkomst kan verhullen en bestaande bindingen kan vervangen.
De import met een jokerteken from math import * kan een variabele met de naam e vervangen door de wiskundige constante.
ImportError
Een ImportError kan optreden wanneer from vraagt om een naam die niet beschikbaar is in een module, ook al heeft Python de module zelf gevonden.
Een ImportError door from math import square_root wijst op de gevraagde naam, niet op een ontbrekende installatie.
IndexError
Een IndexError treedt op wanneer een opzoeking in een sequentie vraagt om een positie die niet bestaat, zoals index 3 in een lijst met drie elementen.
Een IndexError door names[4] is een aanwijzing om de lengte van de lijst en de lusgrenzen die 4 opleverden te controleren.
interpreter
Een interpreter is het programma dat Pythoncode uitvoert; verschillende geïnstalleerde interpreters kunnen verschillende pakketten van derden beschikbaar hebben.
De keuze van de interpreter in de editor verklaart waarom een pakket dat voor een andere Python is geïnstalleerd toch kan ontbreken.
invoervalidatie
Invoervalidatie controleert of gegevens van buitenaf aan de eisen van een programma voldoen en reageert op ongeschikte invoer voordat die wordt gebruikt.
Invoervalidatie met if score < 0 blijft actief wanneer Python wordt uitgevoerd met verwijderde asserties.

K

KeyError
Een KeyError treedt op wanneer een opzoeking in een dictionary om een ontbrekende sleutel vraagt, zodat Python via indexering geen waarde voor die sleutel kan teruggeven.
Een KeyError voor "price" kan onthullen dat de huidige dictionary het verwachte prijselement nooit heeft gekregen.

L

logische fout
Een logische fout zorgt dat een programma zich onjuist gedraagt terwijl de instructies worden uitgevoerd zonder een exceptieverslag te produceren.
Door een logische fout slaat een lus die bij index 1 begint de eerste prijs over en geeft ze een te klein totaal.

M

minimaal reproduceerbaar voorbeeld
Een minimaal reproduceerbaar voorbeeld is de kleinste code en invoer waarbij een fout blijft optreden, zodat de relevante stappen direct kunnen worden onderzocht.
Een minimaal reproduceerbaar voorbeeld kan honderden records terugbrengen tot de twee die nog steeds dezelfde fout veroorzaken.
mislukte test
Een mislukte test is een testresultaat dat wordt veroorzaakt door een onware assertie, bijvoorbeeld wanneer een werkelijke retourwaarde verschilt van de voorgeschreven verwachte waarde.
Een mislukte test met markering F kan tonen dat de functie "B" teruggaf waar de gecontroleerde regel "A" vereiste.
module
Een module is een eenheid Pythoncode, meestal een .py-bestand, waarvan functies en variabelen kunnen worden geïmporteerd voor gebruik in een ander programma.
De module math levert sqrt, zodat een programma vierkantswortels kan berekenen zonder die functie te definiëren.
moduleverhulling (module shadowing)
Moduleverhulling ontstaat wanneer een eerder gevonden module dezelfde naam heeft als de bedoelde module en die tijdens het zoeken bij een import verbergt.
Door moduleverhulling door een lokaal random.py kan een script de bibliotheekfunctie randint missen.
modulezoekpad
Het modulezoekpad is de geordende lijst mappen in sys.path die Python na zijn ingebouwde modules controleert bij het zoeken naar imports.
Een hulpbestand buiten het modulezoekpad kan ModuleNotFoundError opleveren wanneer het script het importeert.

N

naar beneden afgeronde gehele waarde (floor)
De naar beneden afgeronde gehele waarde van een getal is het grootste gehele getal dat niet groter is dan dat getal; math.floor gaat waar nodig in de richting van min oneindig.
De naar beneden afgeronde gehele waarde van -3,2 is -4, dus math.floor(-3.2) verschilt van de conversie met int(-3.2).
naar boven afgeronde gehele waarde (ceiling)
De naar boven afgeronde gehele waarde van een getal is het kleinste gehele getal dat niet kleiner is dan dat getal; math.ceil geeft deze naar boven afgeronde gehele waarde.
Een berekening naar boven rondt 3,4 benodigde verfblikken af op vier hele blikken, genoeg voor de genoemde oppervlakte.
NameError
Een NameError treedt op wanneer Python geen binding kan vinden voor een naam die in een expressie wordt gebruikt, vaak door een typefout of ontbrekende import.
Een NameError voor sqrt na alleen import math betekent dat de functie daar het voorvoegsel math. nodig heeft.

O

onderbrekingspunt (breakpoint)
Een onderbrekingspunt markeert een locatie waar een debugger de uitvoering pauzeert, zodat je die kunt onderzoeken voordat je verdergaat met de volgende code.
Met een onderbrekingspunt vóór een lusbijwerking kun je het huidige totaal vergelijken met het element dat op het punt staat te worden opgeteld.
optimalisatieoptie
De optimalisatieoptie -O verandert de uitvoering van Python door assert-instructies te verwijderen, zodat vereiste validatie niet op die instructies kan vertrouwen.
Als je een script start met de optimalisatieoptie, verdwijnt een controle op een negatieve leeftijd die alleen uit een assertie bestaat.

P

pakket
Een pakket groepeert verwante Pythonmodules, meestal in een map, zodat programma’s een grotere verzameling code kunnen organiseren en hergebruiken.
Een pakket van derden kan meerdere verwante modules leveren die een programma voor verschillende taken importeert.
pip
pip is een installatiehulpmiddel dat Pythondistributies van derden downloadt en beheert voor de interpreter die het uitvoert.
Met python3 -m pip show cowsay vraag je de pip die bij python3 hoort om de installatiegegevens van dat pakket te tonen.
programmeerfout (bug)
Een programmeerfout is een fout waardoor programmagedrag afwijkt van het bedoelde gedrag, waaronder verkeerde antwoorden en onverwacht vastlopen.
Een programmeerfout die de eerste prijs overslaat, kun je reproduceren met een lijst met één element waarvan het verwachte totaal gemakkelijk te controleren is.
pseudowillekeurig getal
Een pseudowillekeurig getal wordt geproduceerd door een deterministisch algoritme waarvan de reeks is ontworpen om willekeurig te lijken voor toepassingen zoals simulaties.
Een pseudowillekeurig getal van random.randint(1, 6) kan een dobbelsteenuitkomst voorstellen in een bordspelsimulatie.
puntnotatie
Met puntnotatie benader je een benoemd attribuut binnen een object of module door een punt tussen de objectnaam en de attribuutnaam te plaatsen.
De puntnotatie in math.sqrt(25) vindt de functie sqrt binnen de al geïmporteerde module math.
PyPI
PyPI is de Python Package Index, een openbare opslagplaats waar uitgevers distributies van derden beschikbaar maken voor installatie.
De PyPI-pagina van een pakket biedt projectinformatie en documentatie die je vóór installatie kunt controleren.

R

randgeval
Een randgeval is ongebruikelijke invoer op een uiterste of bijzondere grens, zoals een lege lijst, die gedrag kan blootleggen dat gewone invoer niet laat zien.
Een randgeval met een lijst met één element kan een totaalfunctie blootleggen die haar lus bij het tweede element begint.
regel uitvoeren zonder functies binnen te gaan (step over)
Regel uitvoeren zonder functies binnen te gaan is een debuggeractie die de huidige regel uitvoert, inclusief aangeroepen functies, zonder hun interne regels te volgen.
Gebruik regel uitvoeren zonder functies binnen te gaan bij een berekeningsaanroep wanneer je het teruggegeven resultaat in de aanroepende code wilt onderzoeken.
regressie
Een regressie is een programmeerfout die ontstaat in eerder werkend gedrag, vaak nadat een aanpassing code heeft gewijzigd waarvan andere functies of tests afhankelijk zijn.
Een regressie kan ervoor zorgen dat een eerder geslaagde test van een totaal met één element mislukt na een wijziging die lege invoer moest herstellen.

S

specificatie
Een specificatie beschrijft het gedrag dat een functie moet bieden en vormt een onafhankelijke basis voor invoer, verwachte resultaten en geldige testcontroles.
De specificatie dat scores van minstens 90 een A opleveren, bepaalt het verwachte antwoord voor een test met precies 90.
stacktrace (traceback)
Een stacktrace beschrijft de actieve aanroepketen bij een niet-afgehandelde exceptie en eindigt met het exceptietype en de melding.
Lees eerst de laatste regel van de stacktrace en volg daarna het frame waar de fout optrad omhoog naar de oorspronkelijke aanroep.
standaardbibliotheek
De standaardbibliotheek is de verzameling modules die bij Python wordt geleverd en bestaande hulpmiddelen biedt zonder afzonderlijke pakketinstallatie.
De standaardbibliotheek bevat math voor berekeningen en random voor simulaties zoals dobbelsteenworpen.
startwaarde voor de toevalsgenerator (seed)
Een startwaarde voor de toevalsgenerator initialiseert een pseudowillekeurige generator, zodat dezelfde reeks aanroepen op dezelfde Pythonversie kan worden herhaald.
Door vóór een simulatie de startwaarde in te stellen kan een programmeur tijdens het debuggen dezelfde reeks opnieuw onderzoeken.
syntaxisfout
Een syntaxisfout betekent dat code de grammaticaregels van Python overtreedt, bijvoorbeeld door een ontbrekende dubbele punt, en verhindert dat het betreffende script normaal start.
Een syntaxisfout na if ready kun je herstellen door de dubbele punt toe te voegen die vóór het ingesprongen blok nodig is.

T

TestCase
Een TestCase is de basisklasse van unittest voor testklassen. Ze levert assertiemethoden en ondersteuning voor het uitvoeren van elke opgespoorde test.
Een klasse die overerft van unittest.TestCase kan self.assertEqual aanroepen binnen haar benoemde testmethoden.
testfout
Een testfout is een testresultaat dat wordt veroorzaakt door een andere onverwachte exceptie dan een mislukte assertie, in de test of de code die deze aanroept.
Een testfout met markering E kan ontstaan wanneer een functie TypeError opwerpt voordat de gelijkheidscontrole een waarde ontvangt.
testmethode
Een testmethode is een functie binnen een testklasse waarvan de naam met test begint, zodat unittest haar controles kan opsporen en uitvoeren.
Een testmethode met de naam test_limit kan een grens afzonderlijk controleren van de test voor gewone invoer.
trekken zonder terugleggen
Trekken zonder terugleggen kiest verschillende invoerposities, zodat elke positie hoogstens één keer wordt geselecteerd, ook als waarden zich herhalen.
Bij trekken zonder terugleggen uit ["A", "A", "B"] kun je beide posities selecteren die "A" bevatten.
TypeError
Een TypeError signaleert een ongeschikt type voor een bewerking of een onjuist aantal argumenten bij een functieaanroep, zoals een ontbrekend verplicht argument.
Een TypeError door "Score: " + 8 wijst op een string en een geheel getal die niet met die expressie kunnen worden samengevoegd.
typosquatting
Typosquatting is publiceren onder een naam die op een andere lijkt om mensen te vangen die bij software-installatie de naam van een vertrouwd project verkeerd typen.
Door de exacte spelling van een project op PyPI te controleren kun je typosquatting vermijden wanneer je een installatieopdracht kopieert.

U

uitvoeringsfout (runtime error)
Een uitvoeringsfout is een probleem dat wordt gedetecteerd terwijl code wordt uitgevoerd, zoals een ongeldige bewerking die op dat moment een exceptie opwerpt.
Een uitvoeringsfout treedt op wanneer een geldige delingsexpressie wordt bereikt met een deler waarvan de waarde nul is.
uitvoeringstabel
Een uitvoeringstabel legt variabelewaarden vast bij opeenvolgende uitvoeringsstappen, zodat je een programma met de hand kunt volgen en de veranderingen kunt onderzoeken.
Een uitvoeringstabel voor een lus die waarden optelt toont het totaal vóór en na de optelling van elk element.
unittest
Een unittest is een kleine geautomatiseerde controle van een onderdeel zoals een functie, waarbij het gedrag voor gekozen invoer wordt vergeleken met een verwacht resultaat.
Een unittest controleert of een prijsfunctie 0 teruggeeft voor een lege lijst wanneer de specificatie dat resultaat vereist.

V

ValueError
Een ValueError signaleert dat een bewerking het type van de invoer accepteert maar de specifieke waarde niet kan gebruiken, zoals ongeldige getaltekst.
Een ValueError door int("6.2") betekent dat de string geen geheel getal in de vereiste vorm beschrijft.
verdeel en heers
Verdeel en heers bakent een zoektocht bij het debuggen af door benodigde tussenwaarden te controleren en het gedeelte te volgen waar ze voor het eerst verkeerd worden.
Verdeel en heers richt de aandacht op conversie als ruwe gegevens correct zijn maar geconverteerde waarden al verkeerd zijn.
voorwaarde voor directe uitvoering (main guard)
Een voorwaarde voor directe uitvoering is een if __name__ == "__main__":-blok dat zijn inhoud bij directe uitvoering uitvoert en die bij een gewone import overslaat.
Een voorwaarde voor directe uitvoering rond main() laat tests de functies van de module importeren zonder de toepassing te starten.

Over deze les

Door StudeliFout melden

Maak je eigen Studiemateriaal

Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.

Aan de slag