- Leren
- Informatica & ICT
- Programmeren
- Inleiding tot programmeren met Python
- Modules en debuggen in Python
Modules en debuggen in Python: fouten zoeken en testen
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
- Importeer bestaande code in een programma met import-instructies, gebruik modules uit de standaardbibliotheek zoals
mathenrandom, verdeel je eigen code over modules en installeer pakketten van derden met pip.- Importeer code in een programma met import-instructiesGebruik
import,from … importenascorrect, benader namen met puntnotatie en maak onderscheid tussen importfouten. - Reken en simuleer met math, random en andere standaardmodulesGebruik de belangrijkste functies van
mathenrandom, vermijd veelvoorkomende valkuilen en leer enkele andere veelgebruikte modules uit de standaardbibliotheek kennen. - Schrijf en importeer je eigen modulesVerdeel code over je eigen
.py-bestanden, importeer ze, voorkom naamconflicten en gebruikif __name__ == "__main__":zodat een bestand zowel kan worden uitgevoerd als geïmporteerd. - Installeer en beheer pakketten met pipInstalleer, bekijk, update en verwijder pakketten van derden van PyPI, importeer ze onder de juiste naam en los veelvoorkomende installatieproblemen op.
- Importeer code in een programma met import-instructies
- 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 bovenZoek het exceptietype, de melding, de regel waar de fout optrad en de aanroepketen die daartoe leidde.
- Herken veelvoorkomende fouten en hun oorzakenKoppel de meest voorkomende exceptietypen aan hun gebruikelijke oorzaken en oplossingen, en herken logische fouten die geen melding geven.
- Lees een stacktrace van onder naar boven
- 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 debuggenReproduceer 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 debuggerBekijk 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.
- Volg een stapsgewijze aanpak om te debuggen
- Gebruik
assertom vast te leggen wat waar moet zijn, schrijf kleine geautomatiseerde tests voor je functies en voer ze uit en lees ze met de standaardmoduleunittest.- Controleer aannames met assert-instructiesSchrijf
assert-instructies met duidelijke meldingen en weet wanneer asserties wel en niet het juiste hulpmiddel zijn. - Schrijf je eerste unittests voor je functiesSchrijf 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 unittestSchrijf tests met
unittest.TestCase, voer ze uit en lees het verslag van geslaagde en mislukte tests en testfouten.
- Controleer aannames met assert-instructies
Modules en debuggen in Python: uitleg
1Hergebruik 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.
| Instructie | Aangemaakte naam | Voorbeeldaanroep |
|---|---|---|
import math | math | math.sqrt(16) |
from math import sqrt | sqrt | sqrt(16) |
import statistics as stats | stats | stats.mean([2, 4, 9]) |
from random import randint as roll | roll | roll(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
| Fout | Wat je controleert |
|---|---|
ModuleNotFoundError door import mathh | De spelling en installatie van de module |
ImportError door from math import square_root | De 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 modulemaakt een modulebinding aan; benader de inhoud met puntnotatie.from module import namemaakt de geselecteerde binding aan; metaskies 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.
| Expressie | Resultaat | Betekenis |
|---|---|---|
math.floor(7.9) | 7 | Grootste gehele getal dat niet groter is dan de waarde |
math.ceil(2.1) | 3 | Kleinste gehele getal dat niet kleiner is dan de waarde |
math.floor(-2.5) | -3 | Naar beneden gaat in de richting van min oneindig |
int(-3.5) | -3 | De conversie kapt af in de richting van nul |
round(2.5) | 2 | Een waarde precies halverwege wordt naar even afgerond |
round(3.5) | 4 | Het 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.
| Aanroep | Resultaat |
|---|---|
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,intenroundbeantwoorden verschillende vragen over afronden.- Gebruik
math.isclosewanneer je berekende zwevendekommagetallen vergelijkt. randintbevat beide grenzen;randrangesluit de eindgrens uit.samplekiest posities zonder terugleggen, dus dubbele invoerwaarden kunnen worden herhaald.shuffleverandert een lijst ter plaatse en geeftNoneterug.- Een vaste startwaarde helpt willekeurig gedrag te reproduceren; voor beveiligingstokens is
secretsnodig.
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
| Terminalopdracht | Taak |
|---|---|
python -m pip list | Geïnstalleerde pakketten en versies weergeven |
python -m pip show requests | Details tonen, waaronder de installatielocatie |
python -m pip install --upgrade requests | Bijwerken naar de nieuwste beschikbare versie |
python -m pip install "requests==2.32.3" | Precies die versie selecteren |
python -m pip uninstall requests | Het 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 pipmet 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.
2Lees 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.
- Regel 2 deelt door
len(values). Wil die deler nul zijn, dan moetvaluesleeg zijn. - Regel 5 roept
average(scores)aan, dus onderzoek descoresdiereportdoorgaf. - 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
| Soort | Wat gebeurt er | Voorbeeld |
|---|---|---|
| Syntaxisfout | Python kan de code niet ontleden | Een ontbrekende dubbele punt na if |
| Uitvoeringsfout | De uitvoering bereikt een ongeldige bewerking | Delen door nul |
| Logische fout | De uitvoering eindigt met verkeerd gedrag | Een 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
| Exceptie | Voorbeeld | Oorzaak |
|---|---|---|
IndexError | [4, 6, 10][3] | De laatste geldige index is 2 |
KeyError | {"apples": 3}["pears"] | De dictionary bevat "pears" niet |
ZeroDivisionError | 10 / 0 | De deler is nul |
AttributeError | math.sqroot(16) | De module bevat sqroot niet |
ModuleNotFoundError | import mathh | Er is geen module onder die naam gevonden |
ImportError | from math import square_root | De 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.
NameErrorgaat over een binding;TypeErrorgaat over een type of aanroepargumenten.ValueErrorgaat over een ongeschikte waarde van een geaccepteerd type.IndexError,KeyErrorenAttributeErrorverwijzen naar verschillende soorten opzoekingen.- Door uitvoer te vergelijken met een verwacht resultaat kun je een logische fout zonder stacktrace ontdekken.
3Vind 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
- Reproduceer: zoek invoer die de programmeerfout steeds laat zien.
- Vermeld het verwachte en werkelijke resultaat: bereken het verwachte resultaat onafhankelijk.
- Vorm een hypothese: noem een mogelijke oorzaak en het voorspelde gedrag.
- Toets de hypothese: onderzoek waarden met uitvoerinstructies, een uitvoeringstabel of een debugger.
- Herstel de oorzaak: maak één gerichte wijziging.
- 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 i | Opgetelde prijs | Totaal ervoor | Totaal erna |
|---|---|---|---|
| 1 | 6 | 0 | 6 |
| 2 | 10 | 6 | 16 |
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:
| Opdracht | Effect |
|---|---|
| Regel uitvoeren zonder functies binnen te gaan | Voer de huidige regel uit, inclusief een aangeroepen functie |
| Functie binnengaan | Ga een functie binnen die op die regel wordt aangeroepen |
| Functie verlaten | Voltooi deze functie en pauzeer na de terugkeer |
| Doorgaan | Voer 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 totaltoonttotal.nvoert de volgende regel uit zonder functies binnen te gaan.sgaat een functieaanroep binnen.cgaat verder met de uitvoering.qbeë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,cenqzijn debuggeropdrachten.- Onderzoek retourwaarden wanneer een functie correct afdrukt maar de aanroepende code faalt.
- Verwijder tijdelijke diagnostische uitvoer en onderbrekingspunten na de reparatie.
4Controleer 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, messagewerptAssertionErrorop als de voorwaarde onwaar is.- Asserties kunnen interne aannames en verwachte functieresultaten controleren.
- Gebruik
ifen een foutmelding of exceptie voor invoer van buitenaf;-Overwijdert asserties. - Een komma binnen
assert (condition, message)maakt een als waar beschouwde tuple. - Gebruik
==voor gelijkheid enmath.isclosevoor 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
| Methode | Controle |
|---|---|
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 vanunittest.TestCase. - Gebruik
self.assertEqualen andere assertiemethoden voor duidelijke controles en verslagen. assertRaisescontroleert een verwachte exceptie; voor vergelijkingen van zwevendekommagetallen kun jeassertAlmostEqualgebruiken.- Voer een testbestand met een voorwaarde voor directe uitvoering rechtstreeks uit of gebruik
python -m unittestom tests op te sporen. - Lees
Fals een mislukte assertie enEals 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
1Bouw een programma uit herbruikbare onderdelen
20 stappen
- 1IntroductieBegin 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.
- 2UitlegDe 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.0af. De eerste maaktmathaan, dus de aanroep gebruikt een punt. De tweede maaktsqrtaan en heeft dus geen modulevoorvoegsel nodig. De verkeerde aanroepstijl werptNameErrorop wanneer die naam niet is gebonden. - 3VoorbeeldBereken de schuine zijde
Met
import mathkun 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)geeft5.0terug. Python evalueert het argument voordat de functie wordt aangeroepen.Het voorvoegsel vertelt een lezer ook waar
sqrtvandaan komt. Een import met een jokerteken verbergt die herkomst en kan bestaande namen vervangen, zoals een variabele met de naame. - 4UitdagingVolg 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
NameErrorop omdat de importstbindt, nietstatistics. Gebruikst.mean([4, 8, 12]), dat8teruggeeft. Een alias kiest de binding in dit programma; hij maakt niet ook de oorspronkelijke modulenaam aan. - 5VoorbeeldRond 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;ceilgeeft3, genoeg hele blikken.round(2.3)geeft slechts2.Voor negatieve invoer betekent naar beneden nog steeds in de richting van min oneindig:
math.floor(-2.5)is-3, terwijlint(-2.5)afkapt in de richting van nul en-2geeft. - 6KernpuntStem 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) # TrueGebruik voor die benaderende vergelijking een controle op nabijheid. Daarnaast blijft de toegestane invoer van een functie van belang:
math.sqrt(-1)werptValueErrorop.De ingebouwde functie
roundhoef je niet te importeren. Bij een waarde precies halverwege kiest ze het naastgelegen even getal:round(2.5)is2enround(3.5)is4. - 7UitlegKies het willekeurige resultaat dat je nodig hebt
Kies na
import randomeen 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)kiestkposities zonder terugleggen.
Twee geselecteerde posities kunnen dezelfde waarde bevatten. Als je in
[1, 1]beide posities trekt, krijg je daarom herhaaldelijk de waarde 1. - 8UitdagingBehoud de geschudde lijst
Welke waarde bevat
namesaan 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.shuffleverandert de bestaande lijst en geeft daarnaNoneterug; de toekenning vervangt de binding met de lijst door die retourwaarde. Gebruikrandom.shuffle(names)op een eigen regel. De nieuwe volgorde van de lijst is willekeurig, maar de retourwaarde staat vast. - 9VerbandHerhaal 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. Gebruiksecretsvoor beveiligingstokens.Andere standaardmodules lossen alledaagse taken op:
statistics.mean([2, 4, 9])geeft5enmediangeeft4.datetime.date.today()geeft de datum van vandaag.sys.argvbevat de naam van het uitgevoerde script gevolgd door de opdrachtregelargumenten. - 10VoorbeeldZet 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 ** 2Een script in dezelfde map kan
import geometryuitvoeren en daarnaprint(geometry.circle_area(2)). Het drukt12.566370614359172af.Importeer het bestand zonder
.py. De eerste string van de functie is haar docstring, diehelp(geometry.circle_area)kan tonen. - 11UitlegEen import voert instructies op moduleniveau uit
Stel dat
geometry.pyeindigt metprint(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_areate 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. - 12VoorbeeldStart 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__", zodatmain()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_areaimporteren zonder de gewone uitvoer van het programma te produceren. - 13UitdagingHoud de functie beschikbaar voor wie importeert
Een bestand definieert
convertbinnen zijnif __name__ == "__main__":-blok. Een nieuw testproces importeert het bestand en kanconvertniet 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. - 14TipControleer het bestand dat een import vindt
Python controleert ingebouwde modules en doorzoekt daarna
sys.pathop volgorde. De map van het script staat normaal gesproken vóór bibliotheekmappen. Een lokaalrandom.pykan daardoor derandomverbergen die je wilde importeren.Geef dat bestand een andere naam, zoals
dice.py. Gebruik voor je eigen hulpfuncties geldige namen zoalsmy_tools.pyen bewaar ze naast het beginnersscript dat ze importeert. Een bestand buiten het zoekpad wordt met een gewone import niet gevonden. - 15VoorbeeldInstalleer in de terminal, importeer in Python
Voer in de terminal uit:
python -m pip install cowsayDaarna kan Pythoncode dit gebruiken:
import cowsay cowsay.cow("Hello, Ada")Het pakket drukt een koe van teksttekens en een tekstballon af.
pipinstalleert code, terwijlimportde binding aanmaakt die je programma gebruikt. De installatieopdracht is geen Pythoninstructie; bij een prompt>>>levert ze ongeldige syntaxis op. - 16UitlegGebruik de pip die hoort bij de uitgevoerde Python
Als een script met
python3wordt uitgevoerd, installeer dan via dezelfde opdracht:python3 -m pip install cowsay python3 game.py-m pipselecteert de pip die bij die interpreter hoort. Op Windows kan je opdracht in plaats daarvanpyzijn.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.
- 17UitdagingMaak onderscheid tussen de installatie- en importnaam
De documentatie van een pakket zegt dat je
Pillowmoet installeren enPILmoet importeren. De installatie slaagt voor de Python die je uitvoert, maarimport Pillowmislukt. 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. - 18TipBekijk een pakket voordat je het wijzigt
python -m pip listtoont geïnstalleerde versies.show requestsgeeft de versie en locatie van één pakket;install --upgrade requestswerkt het bij enuninstall requestsverwijdert het. Elke korte opdracht volgt oppython -m pip.Controleer vóór installatie de exacte PyPI-naam en de projectdocumentatie. Gebruik bij een fout
externally-managed-environmenteen virtuele omgeving voor het project; forceer een installatie niet metsudo pip install. - 19UitdagingVoorspel een import en een latere aanroep
Een nieuwe module
sizes.pybevat deze code. Een ander script voertfrom sizes import batchesuit en daarnaprint(batches(17)). Wat wordt afgedrukt?import math def batches(n): return math.ceil(n / 5) if __name__ == "__main__": print(batches(12))---reveal---
Alleen
4wordt 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 bindingmathbinnensizesis beschikbaar voor de functie. - 20SamenvattingVolg 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
Nonevan 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.
2Volg een fout terug naar de oorzaak
11 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieGebruik het verslag als bewijs
- 2VoorbeeldEen lege lijst bereikt een deling
- 3UitlegZoek het meest recente frame
- 4VoorbeeldVolg het argument terug via de aanroepende code
- 5UitdagingZoek een ongeschikt argument
- 6UitlegMaak onderscheid tussen grammatica, typen en waarden
- 7UitlegVerschillende opzoekingen geven verschillende fouten
- 8VoorbeeldEen programma kan normaal eindigen met een verkeerd totaal
- 9UitdagingVerklaar een mislukte optelling
- 10UitdagingGebruik een bibliotheekframe zonder de bibliotheek de schuld te geven
- 11SamenvattingKies waar je verder zoekt
3Onderzoek een programmeerfout van bewijs tot reparatie
14 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieZorg dat het verkeerde resultaat zich herhaalt
- 2VoorbeeldVermeld het verwachte en werkelijke resultaat
- 3UitlegMaak het vermoeden toetsbaar
- 4VoorbeeldDruk af vóór de bijwerking
- 5VoorbeeldVolg de optellingen met de hand
- 6UitdagingInterpreteer uitvoer na de bijwerking
- 7VoorbeeldHerstel de iteratie zelf
- 8VerbandTest invoer met verschillende vormen opnieuw
- 9TipVerklein een groter probleem
- 10UitdagingControleer een waarde die op een getal lijkt
- 11UitlegPauzeer bij de aanroep die je wilt onderzoeken
- 12UitdagingKies de stapopdracht
- 13UitdagingOnderzoek correcte uitvoer en een verkeerde retourwaarde
- 14SamenvattingBlijf de reparatie koppelen aan bewijs
4Maak van een grensfout een blijvende test
16 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieGeef verwacht gedrag een herhaalbare controle
- 2UitlegEen assertie legt een verwachting vast
- 3UitdagingZoek een controle die niet kan mislukken
- 4KernpuntHoud controles op invoer van buitenaf actief
- 5VoorbeeldKies invoer rond de beoordelingsgrens
- 6VoorbeeldSchrijf een testfunctie die de code importeert
- 7TipVoer de controles uit die je hebt gedefinieerd
- 8UitdagingHerstel een drempelwaarde en bewaar de controle
- 9VerbandTest het teruggegeven resultaat of een geldige eigenschap
- 10VoorbeeldGebruik het klassensjabloon van unittest
- 11UitlegKies de assertie voor het resultaat
- 12VoorbeeldLees een mislukte beoordelingscontrole
- 13UitdagingMaak onderscheid tussen een mislukte test en een testfout
- 14TipControleer wat het opsporen daadwerkelijk heeft uitgevoerd
- 15UitdagingGebruik een verslag om de reparatie te plannen
- 16SamenvattingBewaar een test voor het gedrag dat je hebt hersteld
Modules en debuggen in Python: oefenvragen
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)
Toon antwoordVerberg antwoord
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
random.sample(["blue", "blue", "red"], 2). Waarom kan het resultaat twee waarden "blue" bevatten?Toon antwoordVerberg antwoord
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
Toon antwoordVerberg antwoord
__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
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?Toon antwoordVerberg antwoord
"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
result + 2, waarbij result de retourwaarde van de aanroep is. Waarom ontstaat een TypeError?Toon antwoordVerberg antwoord
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
Toon antwoordVerberg antwoord
Vraag 7 van 10
answer = calculate(7). Je wilt de eerste regel binnen calculate onderzoeken. Welke opdracht gebruik je?Toon antwoordVerberg antwoord
Vraag 8 van 10
charge(6) geeft 3 terug, maar de test verwacht 3 en slaagt. Welke wijziging maakt een nuttige regressietest en herstelt de regel?Toon antwoordVerberg antwoord
Vraag 9 van 10
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?Toon antwoordVerberg antwoord
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
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?Toon antwoordVerberg antwoord
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
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
[6, 3, 2]. Welke verwachte en werkelijke resultaten voor twee nieuwe invoerwaarden leggen het resterende probleem bloot?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)
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
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?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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
random.py en importeert random, maar loopt daarna vast omdat random.randint ontbreekt. Welke eerste wijziging pakt het naamconflict aan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
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?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
import statistics as st is de volgende regel statistics.mean([3, 7]). Er zijn geen andere imports of toekenningen. Wat verklaart de fout?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)
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
python -m pip show cowsay meldt een locatie in Python B en de editor kan cowsay niet importeren. Wat moet je eerst doen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
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
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
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?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
self.assertEqual(lookup("x"), 7) aan. De aanroep van lookup werpt onverwacht KeyError op voordat hij terugkeert. Welk kort resultaat markeert deze test?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
import math. Hoe moet het de vierkantswortelfunctie aanroepen voor 81?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
math.ceil(35 / 8) terug en wat stelt dit voor?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
text_tools.py definieert shorten. Hoe kan een ander bestand in dezelfde map die functie importeren en aanroepen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
>>> en voert pip install cowsay in. Waarom meldt Python ongeldige syntaxis?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
ZeroDivisionError. De frames tonen van boven naar beneden show([]), mean(data) en sum(values) / len(values). Welke keten verklaart de fout het best?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
int("7.25") op?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
[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?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
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")
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
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
aanroepframe
aanroepketen
report-functie naar een average-functie laat zien hoe een lijst de functie bereikte die door de lengte ervan deelde.alias
as kiest voor een geïmporteerde module of een geïmporteerd object; de import bindt die naam in het importerende programma.stats in import statistics as stats kan het script stats.mean([1, 3, 8]) aanroepen.assertie
AssertionError op als die onwaar is.assert count == 3 vergelijkt een intern resultaat met het aantal dat je onafhankelijk verwacht.AssertionError
"wrong total" vestigt de aandacht op de test die het berekende totaal vergeleek.automatisch opsporen van tests
test*.py van unittest.python -m unittest kun je passende bestanden uitvoeren zonder ze elk in een opdracht te noemen.B
bewerking ter plaatse (in-place operation)
random.shuffle(cards) verandert cards en geeft None terug, dus is geen toekenning nodig.C
code op moduleniveau
print aanroept, kan tijdens een import uitvoer produceren, ook wanneer de importerende code geen functie aanroept.D
debuggen
debuggen met uitvoerinstructies
print(f"{i=} {total=}") de lusindex en het totaal op het onderzochte moment van labels.debugger
calculate binnengaan om de argumenten te onderzoeken wanneer de aanroepende code een verkeerd antwoord ontvangt.distributie
beautifulsoup4 wordt onder die naam geïnstalleerd, maar de documentatie zegt dat Pythongebruikers bs4 moeten importeren.docstring
help() kan worden getoond.circle_area kan het straalargument uitleggen en de oppervlakte die aan de aanroepende code wordt teruggegeven.E
exceptie
average stoppen voordat de aanroepende code het berekende gemiddelde afdrukt.F
functie binnengaan (step into)
result = convert(text) wanneer de retourwaarde verkeerd is en de invoertekst correct lijkt.G
grensgeval
H
hypothese
I
import met een jokerteken
* om de openbare namen van een module naar het huidige programma te halen, wat de herkomst kan verhullen en bestaande bindingen kan vervangen.from math import * kan een variabele met de naam e vervangen door de wiskundige constante.ImportError
from vraagt om een naam die niet beschikbaar is in een module, ook al heeft Python de module zelf gevonden.from math import square_root wijst op de gevraagde naam, niet op een ontbrekende installatie.IndexError
names[4] is een aanwijzing om de lengte van de lijst en de lusgrenzen die 4 opleverden te controleren.interpreter
invoervalidatie
if score < 0 blijft actief wanneer Python wordt uitgevoerd met verwijderde asserties.K
KeyError
"price" kan onthullen dat de huidige dictionary het verwachte prijselement nooit heeft gekregen.L
logische fout
M
minimaal reproduceerbaar voorbeeld
mislukte test
F kan tonen dat de functie "B" teruggaf waar de gecontroleerde regel "A" vereiste.module
.py-bestand, waarvan functies en variabelen kunnen worden geïmporteerd voor gebruik in een ander programma.math levert sqrt, zodat een programma vierkantswortels kan berekenen zonder die functie te definiëren.moduleverhulling (module shadowing)
random.py kan een script de bibliotheekfunctie randint missen.modulezoekpad
sys.path die Python na zijn ingebouwde modules controleert bij het zoeken naar imports.ModuleNotFoundError opleveren wanneer het script het importeert.N
naar beneden afgeronde gehele waarde (floor)
math.floor gaat waar nodig in de richting van min oneindig.math.floor(-3.2) verschilt van de conversie met int(-3.2).naar boven afgeronde gehele waarde (ceiling)
math.ceil geeft deze naar boven afgeronde gehele waarde.NameError
sqrt na alleen import math betekent dat de functie daar het voorvoegsel math. nodig heeft.O
onderbrekingspunt (breakpoint)
optimalisatieoptie
-O verandert de uitvoering van Python door assert-instructies te verwijderen, zodat vereiste validatie niet op die instructies kan vertrouwen.P
pakket
pip
python3 -m pip show cowsay vraag je de pip die bij python3 hoort om de installatiegegevens van dat pakket te tonen.programmeerfout (bug)
pseudowillekeurig getal
random.randint(1, 6) kan een dobbelsteenuitkomst voorstellen in een bordspelsimulatie.puntnotatie
math.sqrt(25) vindt de functie sqrt binnen de al geïmporteerde module math.PyPI
R
randgeval
regel uitvoeren zonder functies binnen te gaan (step over)
regressie
S
specificatie
stacktrace (traceback)
standaardbibliotheek
math voor berekeningen en random voor simulaties zoals dobbelsteenworpen.startwaarde voor de toevalsgenerator (seed)
syntaxisfout
if ready kun je herstellen door de dubbele punt toe te voegen die vóór het ingesprongen blok nodig is.T
TestCase
unittest.TestCase kan self.assertEqual aanroepen binnen haar benoemde testmethoden.testfout
E kan ontstaan wanneer een functie TypeError opwerpt voordat de gelijkheidscontrole een waarde ontvangt.testmethode
test begint, zodat unittest haar controles kan opsporen en uitvoeren.test_limit kan een grens afzonderlijk controleren van de test voor gewone invoer.trekken zonder terugleggen
["A", "A", "B"] kun je beide posities selecteren die "A" bevatten.TypeError
"Score: " + 8 wijst op een string en een geheel getal die niet met die expressie kunnen worden samengevoegd.typosquatting
U
uitvoeringsfout (runtime error)
uitvoeringstabel
unittest
V
ValueError
int("6.2") betekent dat de string geen geheel getal in de vereiste vorm beschrijft.verdeel en heers
voorwaarde voor directe uitvoering (main guard)
if __name__ == "__main__":-blok dat zijn inhoud bij directe uitvoering uitvoert en die bij een gewone import overslaat.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.