Grundlagen: Python-Module, Fehlersuche und Tests

Lerne, auf vorhandenem Code aufzubauen und eigenen Code zuverlässig zum Laufen zu bringen. Importiere Module aus Pythons Standardbibliothek wie math und random, schreibe eigene Module und installiere Pakete von PyPI mit pip. Lies anschließend Tracebacks und Fehlermeldungen, finde Programmfehler durch schrittweise Fehlersuche und prüfe deine Funktionen mit assert-Anweisungen und ersten Unit-Tests.

AnfängerEinheit 9 von 10 in Kurs: Python-Programmierung – Schleifen, Funktionen, Listen und Dateien

Was du lernst

  1. Binde fertigen Code mit import-Anweisungen in ein Programm ein, verwende Standardbibliotheksmodule wie math und random, teile eigenen Code in Module auf und installiere Pakete von Drittanbietern mit pip.
    • Code mit import-Anweisungen in ein Programm einbinden
      Verwende import, from … import und as richtig, greife mit Punktnotation auf Namen zu und unterscheide Importfehler.
    • Mit math, random und anderen Standardmodulen rechnen und simulieren
      Verwende die wichtigsten Funktionen von math und random, vermeide häufige Fehler und lerne einige weitere alltägliche Standardbibliotheksmodule kennen.
    • Eigene Module schreiben und importieren
      Teile Code auf eigene .py-Dateien auf, importiere sie, vermeide Namenskonflikte und verwende if __name__ == "__main__":, damit eine Datei sowohl ausgeführt als auch importiert werden kann.
    • Pakete mit pip installieren und verwalten
      Installiere, untersuche, aktualisiere und entferne Pakete von Drittanbietern von PyPI, importiere sie unter dem richtigen Namen und löse die üblichen Installationsprobleme.
  2. Nutze Pythons Fehlerausgabe, um herauszufinden, wo und warum ein Programm gescheitert ist, und unterscheide Syntaxfehler, Laufzeitfehler und Logikfehler.
    • Einen Traceback von unten nach oben lesen
      Finde den Ausnahmetyp, die Meldung, die fehlerauslösende Zeile und die Aufrufkette, die dorthin geführt hat.
    • Häufige Fehler und ihre Ursachen erkennen
      Ordne die häufigsten Ausnahmetypen ihren üblichen Ursachen und Lösungen zu und erkenne Logikfehler, die keine Meldung erzeugen.
  3. Finde die Ursache eines Programmfehlers durch schrittweises Vorgehen statt durch Raten und untersuche ein laufendes Programm mit print-Anweisungen und einem Debugger.
    • Bei der Fehlersuche schrittweise vorgehen
      Reproduziere einen Programmfehler, stelle eine Hypothese auf und prüfe sie, grenze die Ursache ein, behebe sie und teste erneut.
    • Ein Programm mit print-Anweisungen, Ablauftabellen und einem Debugger untersuchen
      Beobachte, wie sich Werte während der Codeausführung ändern, indem du Ausgaben hinzufügst, den Ablauf von Hand nachvollziehst oder an Haltepunkten pausierst.
  4. Verwende assert, um festzuhalten, was wahr sein muss, schreibe kleine automatisierte Tests für deine Funktionen und führe sie mit dem Standardmodul unittest aus und lies ihre Ergebnisse.
    • Annahmen mit assert-Anweisungen prüfen
      Schreibe assert-Anweisungen mit klaren Meldungen und erkenne, wann Zusicherungen das richtige Werkzeug sind und wann nicht.
    • Erste Unit-Tests für eigene Funktionen schreiben
      Schreibe Testfunktionen mit Zusicherungen, wähle typische Fälle, Grenzwertfälle und Randfälle und nutze fehlgeschlagene Tests, um Fehler zu finden und zu beheben.
    • Tests mit unittest organisieren und ausführen
      Schreibe Tests mit unittest.TestCase, führe sie aus und lies den Bericht über bestandene Tests, fehlgeschlagene Tests und Testfehler.

Python-Module, Fehlersuche und Tests einfach erklärt

4 Kapitel

1

Module wiederverwenden und Pakete installieren

Mit importiertem Code kann ein kleines Programm Berechnungen, Simulationen und Werkzeuge nutzen, die anderswo geschrieben wurden. Du wählst eine Importform, arbeitest mit Funktionen der Standardbibliothek und ordnest deine eigenen Funktionen so an, dass eine andere Datei sie wiederverwenden kann. Bei der Installation stellt sich eine weitere Frage: In welchem Python wird ein Paket eines Drittanbieters installiert? Wenn du diesen Zusammenhang verstehst, kannst du ein fehlendes Modul leichter diagnostizieren und die Namen in jedem Programm übersichtlich halten.

1.1 Ein Modul oder ausgewählte Namen importieren

Ein Modul enthält Python-Code, den ein anderes Programm wiederverwenden kann. Die meisten Module sind .py-Dateien. Die Standardbibliothek wird mit Python geliefert; Code von Drittanbietern muss separat installiert werden. Ein Paket bündelt zusammengehörige Module, meist in einem Ordner.

Den Aufruf passend zum Import schreiben

Ein Import erzeugt Namen in deinem Programm. Die gewählte Form bestimmt, wie du den importierten Code aufrufst.

AnweisungErzeugter NameBeispielaufruf
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)

Punktnotation bedeutet, einen Namen innerhalb eines Moduls oder Objekts nachzuschlagen. In math.sqrt(16) findet Python sqrt innerhalb von math und ruft es mit 16 auf. Das Ergebnis ist 4.0. Die Konstante math.pi braucht keine Aufrufklammern, weil sie ein Wert und keine Funktion ist.

Nach import math löst sqrt(16) allein einen NameError aus: Das Programm hat einen Namen für das Modul, aber keinen eigenen Namen für sqrt. Nach alleinstehendem from math import sqrt löst der umgekehrte Fehler math.sqrt(16) ebenfalls einen NameError aus, weil math nicht gebunden wurde. Ein Alias ersetzt den üblichen Namen der importierten Bindung: import statistics as stats erzeugt stats, nicht beide Namen.

Dieselbe Berechnung auf zwei Arten durchführen

Ein rechtwinkliges Dreieck hat die Seitenlängen 3 und 4. Quadriere zuerst die Seitenlängen und addiere sie; ziehe dann die Quadratwurzel.

import math

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

Der Ausdruck innerhalb des Aufrufs wird zu 9 + 16, dann zu 25; sqrt gibt 5.0 zurück. Mit from math import sqrt schreibst du stattdessen length = sqrt(3**2 + 4**2). Der vorangestellte Modulname macht die Herkunft einer Funktion sichtbar und hält die übrigen Namen des Moduls aus dem Namensraum deines Programms heraus. Die Bindung math selbst kann weiterhin eine frühere Variable namens math ersetzen.

Namen übersichtlich halten

Vermeide from math import *. Dieser Wildcard-Import bringt öffentliche Namen in dein Programm, ohne sie einzeln zu nennen. Zum Beispiel ändert e = 5, gefolgt von diesem Import, den Wert von e zu 2.718281828459045. Ein scheinbar unbeteiligter Import kann daher eine spätere Berechnung verändern. PEP 8 empfiehlt explizite Importe und setzt sie an den Anfang, mit einem Modul pro Zeile: zuerst die Standardbibliothek, danach Pakete von Drittanbietern, zuletzt eigene Module.

Python führt den Code auf Modulebene beim ersten Import eines Moduls während eines Programmlaufs aus. Spätere Importe verwenden das geladene Modul wieder; sie starten es nicht erneut.

Anhand des Fehlers die Lösung wählen
FehlerWas du prüfen solltest
ModuleNotFoundError bei import mathhSchreibweise und Installation des Moduls
ImportError bei from math import square_rootDer vom Modul angeforderte Name
AttributeError bei math.sqroot(16)Der Name nach dem Punkt

Führe in der interaktiven Shell import math und dann dir(math) aus, um die Namen des Moduls aufzulisten. Führe help(math.sqrt) aus, um die Dokumentation einer Funktion zu lesen. Die offizielle Python-Bibliotheksreferenz erklärt ihre Argumente und ihr Ergebnis.

Wichtige Erkenntnisse

  • import module erzeugt eine Modulbindung; auf den Inhalt greifst du mit Punktnotation zu.
  • from module import name erzeugt die ausgewählte Bindung; mit as wählst du einen Alias.
  • Explizite Importe halten die Herkunft von Namen erkennbar und verringern unbeabsichtigtes Ersetzen.
  • Importfehler unterscheiden zwischen einem nicht gefundenen Modul, einem nicht verfügbaren importierten Namen und einem fehlenden Attribut.
  • dir() listet Namen auf; help() erklärt, wie du einen davon verwendest.

1.2 Funktionen aus math und random auswählen

Die Standardbibliothek stellt getestete Werkzeuge für Berechnungen und Simulationen bereit. Welche Funktion du wählst, hängt vom benötigten Ergebnis ab: einer ganzzahligen Anzahl, einem gerundeten Messwert, einem zufälligen Element oder einer neu angeordneten Liste.

Runden hat mehrere Bedeutungen

Nach import math gibt math.sqrt(16) die Gleitkommazahl 4.0 zurück. math.pi und math.e liefern die Konstanten 3.141592653589793 und 2.718281828459045. math.factorial(5) multipliziert die ganzen Zahlen von 1 bis einschließlich 5 und gibt 120 zurück.

AusdruckErgebnisBedeutung
math.floor(7.9)7Größte ganze Zahl, die nicht größer als der Wert ist
math.ceil(2.1)3Kleinste ganze Zahl, die nicht kleiner als der Wert ist
math.floor(-2.5)-3Abrunden erfolgt in Richtung minus unendlich
int(-3.5)-3Die Umwandlung schneidet in Richtung null ab
round(2.5)2Ein Wert genau in der Mitte wird zur geraden Zahl gerundet
round(3.5)4Die benachbarte gerade ganze Zahl ist 4

Für 23 Quadratmeter Wand und 10 Quadratmeter pro Farbdose ergibt die Division 2.3 Dosen. Um ganze Dosen zu kaufen, brauchst du math.ceil(23 / 10), das 3 zurückgibt. round(2.3) ergibt 2 und damit zu wenig Farbe.

Die eingebaute Funktion round() braucht keinen Import. Für einen Kreis mit Radius 2 ergibt round(math.pi * 2 ** 2, 2) den Wert 12.57. Runden ändert die Genauigkeit einer Zahl; das ist eine andere Aufgabe, als genügend ganze Behälter zu kaufen.

Definitionsbereiche und Vergleiche von Gleitkommazahlen prüfen

math.sqrt(-1) löst ValueError aus, weil es für diese Eingabe keine reelle Quadratwurzel gibt. Auch bei berechneten Gleitkommazahlen ist Vorsicht nötig: Aufgrund der binären Speicherung ist 0.1 + 0.2 == 0.3 gleich False. math.isclose(0.1 + 0.2, 0.3) ist True; verwende es für einen näherungsweisen Vergleich berechneter Gleitkommazahlen.

Die Zufallsoperation auswählen

Das Modul random erzeugt mit einem Algorithmus Pseudozufallsergebnisse.

AufrufErgebnis
random.randint(1, 6)Eine ganze Zahl von 1 bis einschließlich 6
random.randrange(1, 6)Eine ganze Zahl von 1 bis einschließlich 5
random.random()Eine Gleitkommazahl ab 0,0 und kleiner als 1,0
random.uniform(a, b)Eine Gleitkommazahl zwischen den angegebenen Endpunkten
random.choice(items)Ein Element
random.sample(items, k)Elemente von k Positionen, ohne Zurücklegen
random.shuffle(items)Ordnet die vorhandene Liste neu; gibt None zurück

Schreibe random.shuffle(cards) in eine eigene Zeile. Weist du das Ergebnis wieder cards zu, geht die Bindung an die Liste verloren, weil sie durch None ersetzt wird. Positionen zu ziehen ist außerdem etwas anderes, als unterschiedliche Werte zu verlangen: random.sample([1, 1], 2) gibt [1, 1] zurück.

Eine reproduzierbare Simulation ausführen
import random

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

Sechs von 36 gleich wahrscheinlichen Paaren ergeben zusammen 7, deshalb liegt die Anzahl meist nahe bei 167, ändert sich aber zwischen den Läufen. Um eine Folge für die Fehlersuche zu reproduzieren, rufe vor dem Erzeugen der Werte random.seed(42) auf und verwende dieselbe Python-Version und Aufruffolge. Verwende für Passwörter oder Sicherheitstoken secrets.

Weitere alltägliche Werkzeuge finden

statistics.mean([2, 4, 9]) gibt 5 zurück; statistics.median([2, 4, 9]) gibt 4 zurück. datetime.date.today() liefert das heutige Datum. Nach import sys enthält sys.argv den Skriptnamen gefolgt von seinen Argumenten: Der Aufruf python greet.py Ada liefert ['greet.py', 'Ada'].

Wichtige Erkenntnisse

  • floor, ceil, int und round beantworten unterschiedliche Fragen zum Runden.
  • Verwende math.isclose, wenn du berechnete Gleitkommazahlen vergleichst.
  • randint schließt beide Endpunkte ein; randrange schließt seine Endgrenze aus.
  • sample wählt Positionen ohne Zurücklegen aus, sodass doppelte Eingabewerte wiederholt auftreten können.
  • shuffle verändert eine Liste direkt und gibt None zurück.
  • Ein fester Startwert hilft, zufälliges Verhalten zu reproduzieren; für Sicherheitstoken brauchst du secrets.

1.3 Eine Datei wiederverwendbar machen, ohne ihr Programm zu starten

Eine Funktion lässt sich leichter wiederverwenden, wenn sie in einem Modul mit klarer Aufgabe steht. Ein anderes Programm kann diese Funktion importieren und ein Test kann sie prüfen, ohne dass jemand die gesamte Anwendung ausführen muss.

Die Funktion vom aufrufenden Code trennen

Speichere diesen Code 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

Speichere im selben Ordner diesen aufrufenden Code als main.py:

import geometry

print(geometry.circle_area(2))

Führe python main.py aus. Python findet geometry, erstellt dessen Funktion und anschließend führt der aufrufende Code diese Funktion aus. Das ausgegebene Ergebnis ist 12.566370614359172. Importiere ohne die Endung .py. Ein gültiger Modulname verwendet Buchstaben, Ziffern und Unterstriche und beginnt mit einem gültigen Zeichen; my_tools.py funktioniert mit import my_tools, während import my-tools ungültige Syntax ist.

Die Zeichenketten am Anfang des Moduls und der Funktion sind Docstrings. Sie beschreiben den Zweck des Codes und erscheinen in help(geometry) und help(geometry.circle_area).

Verstehen, was ein Import ausführt

Beim ersten Import führt Python die Anweisungen des Moduls auf Modulebene der Reihe nach aus. Eine def-Anweisung erstellt eine Funktion; sie führt deren Körper nicht aus. Ein ungeschütztes print(circle_area(2)) am Ende von geometry.py würde dagegen beim Import eine Ausgabe erzeugen.

Dieser Nebeneffekt ist wichtig, wenn ein Modul Eingabeaufforderungen oder eine Programmschleife enthält. Ein Test, der nur circle_area benötigt, sollte nicht das Programm starten und dessen Eingabeaufforderungen beantworten müssen.

Den Start schützen, die Funktion verfügbar halten

Füge dies unterhalb der wiederverwendbaren Funktion in geometry.py ein:

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

if __name__ == "__main__":
    main()

Python setzt __name__ für jedes Modul. Bei einer direkten Ausführung mit python geometry.py wird es auf "__main__" gesetzt, sodass die Bedingung wahr ist und main() aufgerufen wird. Beim Import von geometry wird es auf "geometry" gesetzt, sodass Python den Aufruf überspringt. Die Definitionen oberhalb der Schutzbedingung bleiben in beiden Fällen verfügbar.

Setze circle_area selbst nicht innerhalb der Schutzbedingung. Importierender Code braucht diese Definition auch dann, wenn die Startbedingung falsch ist. Die Schutzbedingung steuert, wann die Anwendung startet; sie hindert Python nicht daran, das Modul zu laden.

Wissen, wo Python sucht

Python prüft eingebaute Module wie sys und dann der Reihe nach die Ordner in sys.path. Normalerweise steht der Ordner des laufenden Skripts an erster Stelle dieses Pfads, gefolgt von den Ordnern der Standardbibliothek und der installierten Pakete. Eigene Dateien neben dem ausgeführten Skript aufzubewahren, ist eine einfache Anordnung für ein Anfängerprojekt. Ein Modul außerhalb des Suchpfads kann durch einen gewöhnlichen Import nicht gefunden werden.

Diese Reihenfolge kann auch ein Bibliotheksmodul verdecken. Speicherst du dein Programm als random.py, kann dessen import random deine Datei statt der Bibliothek laden. Ein späteres random.randint(1, 6) löst dann AttributeError aus. Benenne die Datei um, zum Beispiel in dice.py; Python 3.13 und spätere Versionen können der Fehlermeldung einen Hinweis zum Umbenennen hinzufügen.

Ein geladenes Modul wird innerhalb desselben Laufs wiederverwendet. Änderst du in einer interaktiven Shell die Datei und importierst sie erneut, bleibt die geladene Version erhalten. Starte die Shell neu, bevor du deine Änderungen testest.

Wichtige Erkenntnisse

  • Importiere deine eigene .py-Datei über ihren Modulnamen ohne Dateiendung.
  • Ein Import führt Anweisungen auf Modulebene aus, während Funktionskörper auf Aufrufe warten.
  • Halte wiederverwendbare Definitionen außerhalb des __main__-Schutzes und den Programmstart innerhalb davon.
  • Eine lokale Datei kann ein gleichnamiges Bibliotheksmodul verdecken.
  • Starte eine interaktive Shell neu, um ein bearbeitetes Modul erneut zu testen.

1.4 Pakete für das verwendete Python installieren

Pakete von Drittanbietern ergänzen Code, der nicht mit Python geliefert wird. PyPI, der Python Package Index unter https://pypi.org, beherbergt diese Projekte. pip lädt sie herunter und installiert sie für eine bestimmte Python-Installation.

Erst das Terminal, dann Python verwenden

Ein Terminalbefehl und eine Python-Anweisung gehören an unterschiedliche Stellen. Die Eingabeaufforderung >>> bedeutet, dass du dich in Pythons interaktiver Shell befindest. Gibst du dort pip install requests ein, erhältst du SyntaxError; Python kann es nicht als Anweisung lesen.

Führe in deinem Terminal aus:

python -m pip install cowsay

Schreibe danach Folgendes in ein Python-Programm:

import cowsay

cowsay.cow("Hello, Ada")

Das Programm gibt eine Kuh aus Textzeichen neben einer Sprechblase mit der Nachricht aus. Die Installation macht das Paket verfügbar; der Import erzeugt die Bindung des Programms an das Paket.

pip auf deinen Interpreter abstimmen

Die Form -m pip weist das angegebene Python an, sein eigenes pip auszuführen. Verwende den Befehl, mit dem du deine Programme startest: unter macOS oder Linux häufig python3, unter Windows py.

python3 -m pip install cowsay
python3 game.py

Beide Zeilen wählen denselben Python-Befehl. Meldet eine Installation Erfolg, aber ein Skript löst weiterhin ModuleNotFoundError aus, vergleiche das zur Installation verwendete Python mit dem, das das Skript ausführt. Ein Editor kann einen anderen Interpreter ausgewählt haben als dein Terminal. Verwende das pip des ausgewählten Interpreters, bevor du den Import änderst.

Eine Installation untersuchen und pflegen
TerminalbefehlAufgabe
python -m pip listInstallierte Pakete und Versionen auflisten
python -m pip show requestsDetails einschließlich des Installationsorts anzeigen
python -m pip install --upgrade requestsAuf die neueste verfügbare Version aktualisieren
python -m pip install "requests==2.32.3"Genau diese Version auswählen
python -m pip uninstall requestsDas Paket entfernen

Eine genaue Versionsangabe ist nützlich, wenn du das Verhalten genau dieser Version brauchst. Mit show kannst du prüfen, an welchem Ort pip tatsächlich etwas geändert hat.

Den Namen in der Dokumentation prüfen

Der für pip eingegebene Distributionsname kann sich vom Importnamen unterscheiden. Installiere beautifulsoup4 und verwende dann import bs4; installiere Pillow und verwende dann import PIL. Wiederholt einen Importnamen zu installieren, ist keine sinnvolle Lösung, wenn die Dokumentation eine anders benannte Distribution angibt.

Pythons Standardbibliothek, einschließlich math, random und unittest, wird bereits mit Python geliefert. Diese Module müssen nicht mit pip installiert werden.

Eine verwaltete Installation beachten

Einige Betriebssysteme und Paketverwaltungen schützen ihr Python mit einem externally-managed-environment-Fehler. Das bedeutet, dass eine direkte Installation gesperrt ist, damit die verwaltete Installation konsistent bleibt. Verwende eine virtuelle Umgebung, also einen eigenen Python- und Paketordner für das Projekt. Erzwinge die Installation nicht mit sudo pip install.

Jeder kann auf PyPI veröffentlichen. Prüfe vor der Installation die genaue Schreibweise und lies die Projektseite und die Dokumentation. Ähnlich aussehende Namen können Versuche von Typosquatting sein. Bevorzuge etablierte, gepflegte Pakete und installiere die, die dein Programm tatsächlich braucht.

Wichtige Erkenntnisse

  • Führe pip-Befehle in einem Terminal und Importe in Python-Code aus.
  • Verwende python -m pip mit demselben Interpreterbefehl, der das Programm ausführt.
  • Prüfe den Importnamen in der Dokumentation; er kann vom Installationsnamen abweichen.
  • Verwende pip, um ein Paket zu untersuchen, zu aktualisieren, eine Version auszuwählen oder es zu entfernen.
  • Ein verwaltetes Python kann eine virtuelle Umgebung für das Projekt erforderlich machen.
  • Prüfe Schreibweise und Dokumentation des Pakets, bevor du Code von Drittanbietern installierst.
2

Fehler und Tracebacks lesen

Pythons Fehlerausgabe hält sowohl die fehlgeschlagene Operation als auch die Aufrufe fest, die dorthin geführt haben. Wenn du diese Hinweise der Reihe nach liest, findest du einen sinnvollen Ausgangspunkt, statt die erste Zeile zu ändern, die du erkennst. Du verfolgst einen Traceback bis zu seiner Eingabe zurück, unterscheidest häufige Ausnahmetypen und erkennst den weniger auffälligen Fall, in dem ein Programm normal läuft, aber das falsche Ergebnis liefert. Das erwartete Verhalten gibt dir etwas Konkretes, das du prüfen kannst.

2.1 Einen Traceback bis zur fehlerhaften Eingabe zurückverfolgen

Ein Traceback zeigt dir, welche Aufrufe aktiv waren, als eine unbehandelte Ausnahme das Programm stoppte. Er gibt dir sowohl einen Ausgangspunkt für das Lesen als auch einen Weg zurück zu dem Wert, der den Fehler verursacht hat.

Mit der letzten Zeile beginnen

Betrachte dieses vollständige Programm in scores.py:

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

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

report([])

Die letzte Zeile seines Fehlerberichts lautet ZeroDivisionError: division by zero. Sie nennt den Ausnahmetyp und beschreibt die fehlgeschlagene Operation. Beginne dort und lies dann nach oben bis zur Codestelle direkt darüber.

Ein vereinfachter Traceback ohne Markierungen der Ausdrücke lautet:

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
Jeden Aufrufrahmen als aktiven Aufruf lesen

Ein Aufrufrahmen nennt Datei, Zeilennummer und Funktion, gefolgt vom relevanten Code. in <module> bezeichnet Code auf Modulebene. Der älteste Aufruf steht oben, der neueste unten. Liest du von unten, kehrst du diese Reihenfolge um: So kannst du zuerst fragen, was fehlgeschlagen ist, und danach, wie die Ausführung dorthin gelangt ist.

  1. Zeile 2 dividiert durch len(values). Damit dieser Divisor null ist, muss values leer sein.
  2. Zeile 5 ruft average(scores) auf, untersuche also die von report übergebenen Werte scores.
  3. Zeile 8 übergibt [], die leere Liste. Das erklärt, wie der Divisor null in die Berechnung gelangt ist.

Die fehlerauslösende Zeile und die Ursache hängen zusammen, können aber an unterschiedlichen Stellen liegen. Die Division zu ersetzen, ohne zu entscheiden, was eine leere Liste bedeuten soll, würde die Frage nach dem gewünschten Verhalten verdecken. Entweder muss der aufrufende Code eine leere Liste vermeiden oder das Verhalten der Funktion bei leerer Eingabe muss festgelegt werden.

Hervorhebungen nutzen, ohne von ihrer genauen Form abzuhängen

Python 3.11 und spätere Versionen können die Markierungen ^ und ~ ergänzen, um den fehlerauslösenden Teil eines Ausdrucks zu zeigen. Sie helfen, wenn eine Zeile mehrere Operationen enthält. Die genaue Hervorhebung variiert zwischen Versionen, doch die Aufrufstellen und die Ausnahmemeldung geben weiterhin die Lesereihenfolge vor.

Ein Traceback kann Aufrufrahmen aus der Standardbibliothek oder einem installierten Paket enthalten. Finde den untersten Aufrufrahmen in deinem eigenen Code und untersuche die dort übergebenen Argumente. Ein Aufrufrahmen einer Bibliothek gibt einen Hinweis auf die Stelle; er belegt nicht, dass die Bibliothek den Programmfehler enthält.

Eine Syntaxfehlermeldung erkennen

Ein Syntaxfehler im gestarteten Skript verhindert dessen Ausführung. Python meldet eine Datei, eine Zeile, eine Markierung und eine Meldung ohne die übliche Traceback-Kopfzeile. Zum Beispiel fehlt bei if True der Doppelpunkt; bei total = sum([1, 2, 3] bleibt eine Klammer offen.

Die markierte Stelle zeigt, wo Python bemerkt hat, dass es den Code nicht analysieren kann. Sieht diese Zeile gültig aus, prüfe die vorhergehende Zeile auf ein nicht geschlossenes Anführungszeichen oder eine offene Klammer. Wenn das gestartete Skript nicht ausgeführt wurde, gibt es keine Kette von Laufzeitaufrufen, die du verfolgen könntest.

Ein gewöhnlicher Programmlauf stoppt bei seiner ersten unbehandelten Ausnahme. Behebe dieses Problem und führe das Programm erneut aus, um später auftretende Probleme sichtbar zu machen.

Wichtige Erkenntnisse

  • Lies zuerst Ausnahmetyp und Meldung, dann den fehlerauslösenden Aufrufrahmen und seine Aufrufer.
  • Aufrufrahmen reichen vom ältesten aktiven Aufruf oben bis zum neuesten unten.
  • Verfolge den falschen Wert zurück; seine Quelle kann vor dem Absturz liegen.
  • Ein Syntaxfehler im gestarteten Skript wird vor dessen Ausführung gemeldet.

2.2 Falsche Namen, Datentypen, Werte und Ergebnisse unterscheiden

Der Name eines Fehlers grenzt die Suche ein, und seine Meldung liefert Details zu den beteiligten Werten. Ein Programm kann auch falsch sein, ohne eine Ausnahme auszulösen. Deshalb gehört es weiterhin zur Fehlersuche, die erwartete Ausgabe zu überprüfen.

Drei Arten von Problemen unterscheiden
ArtWas geschiehtBeispiel
SyntaxfehlerPython kann den Code nicht analysierenEin fehlender Doppelpunkt nach if
LaufzeitfehlerDie Ausführung erreicht eine ungültige OperationDivision durch null
LogikfehlerDie Ausführung endet mit falschem VerhaltenEine Schleife überspringt einen Preis

IndentationError ist eine Art von SyntaxError. Ein Funktionskörper muss eingerückt sein; ein fehlender eingerückter Block stoppt den Code vor der Ausführung. Prüfe auch auf nicht geschlossene Anführungszeichen oder Klammern und falsch geschriebene Schlüsselwörter.

Namen und Datentypen genau lesen

Ein NameError bedeutet, dass das Programm einen Namen an dieser Stelle nicht kennt. In prnt("hi") ist die eingebaute Funktion print gemeint. Ein Name kann auch vor der Zuweisung verwendet worden sein oder ein Import kann fehlen.

Ein TypeError bedeutet, dass eine Operation einen ungeeigneten Datentyp oder ein Aufruf die falsche Anzahl von Argumenten erhalten hat. "Age: " + 30 mischt eine Zeichenkette und eine ganze Zahl. Schreibe "Age: " + str(30) oder f"Age: {30}". Benötigt area die Argumente w und h, ist auch area(3) ein TypeError, diesmal wegen eines fehlenden Arguments.

Die Meldung unterscheidet diese Ursachen. In can only concatenate str (not "int") to str nennt Python die Datentypen, die aufeinandergetroffen sind. Nach age = input("Age: ") ist age Text. age + 1 schlägt fehl; bei einer ganzzahligen Eingabe führt int(age) + 1 eine Rechnung aus.

Ein ValueError bedeutet, dass der Datentyp der Eingabe akzeptiert wird, ihr Wert aber ungeeignet ist. int("12.5") erhält eine Zeichenkette, also einen akzeptierten Eingabetyp, aber der Text stellt keine ganze Zahl in der erforderlichen Form dar. math.sqrt(-1) enthält einen weiteren ungeeigneten Wert für eine Berechnung mit reellen Zahlen.

Positionen, Schlüssel und Attribute prüfen
AusnahmeBeispielUrsache
IndexError[4, 6, 10][3]Der letzte gültige Index ist 2
KeyError{"apples": 3}["pears"]Dem Wörterbuch fehlt "pears"
ZeroDivisionError10 / 0Der Divisor ist null
AttributeErrormath.sqroot(16)Dem Modul fehlt sqroot
ModuleNotFoundErrorimport mathhUnter diesem Namen wird kein Modul gefunden
ImportErrorfrom math import square_rootDem Modul fehlt dieser importierte Name

Divisoren mit dem Wert null führen auch bei // und % zu Fehlern. Eine fehlende Listenposition und ein fehlender Wörterbuchschlüssel betreffen unterschiedliche Zugriffe, auch wenn in beiden Fällen etwas Fehlendes angefordert wird.

Ein plausibel aussehendes Ergebnis prüfen
def total_price(prices):
    total = 0
    for i in range(1, len(prices)):
        total += prices[i]
    return total

Für [4, 6, 10] gibt dies 16 statt 20 zurück. Es gibt keine Ausnahme: Die Indizes 1 und 2 existieren, also ist jede Operation zulässig. Die Schleife beginnt zu spät und überspringt Index 0. Der Fehler wird sichtbar, wenn du die Ausgabe mit der beabsichtigten Summe vergleichst.

Schlage bei einer unbekannten Ausnahme ihren Typ und die allgemeine Meldung in der offiziellen Python-Dokumentation nach. Entferne deine eigenen Pfade und Eingabewerte aus einer Suchanfrage; sie erklären selten die allgemeine Regel.

Wichtige Erkenntnisse

  • Syntaxfehler verhindern die Analyse des Codes; Laufzeitfehler treten während der Ausführung auf; Logikfehler führen zu falschem Verhalten.
  • NameError betrifft eine Bindung; TypeError betrifft einen Datentyp oder Aufrufargumente.
  • ValueError betrifft einen ungeeigneten Wert eines akzeptierten Datentyps.
  • IndexError, KeyError und AttributeError beziehen sich auf unterschiedliche Arten des Zugriffs.
  • Der Vergleich der Ausgabe mit einem erwarteten Ergebnis kann einen Logikfehler ohne Traceback aufdecken.
3

Die Ursache eines Programmfehlers finden

Ein falsches Ergebnis lässt sich leichter untersuchen, wenn du es reproduzieren und genau sagen kannst, wie es sich vom erwarteten Ergebnis unterscheidet. Du machst aus dieser Beobachtung eine überprüfbare Vermutung, grenzt die Suche auf ein kleines Stück Code ein und untersuchst die entscheidenden Werte. Ausgaben, Ablauftabellen und die Bedienelemente eines Debuggers bieten verschiedene Möglichkeiten, die Ausführung zu beobachten. Nach einer gezielten Korrektur hilft die Prüfung zuvor funktionierender Fälle zu erkennen, welches Verhalten die Änderung beeinflusst hat.

3.1 Eine Ursache prüfen, bevor du den Code änderst

Ein Programmfehler ist ein Unterschied zwischen beabsichtigtem und tatsächlichem Verhalten. Bei der Fehlersuche und Fehlerbehebung findest und behebst du die Ursache. Eine hilfreiche Fehlersuche macht aus einer Beobachtung eine überprüfbare Erklärung und ändert den Code anschließend aufgrund von Belegen.

Den Fehler wiederholt auslösen

Halte eine konkrete Eingabe und das Ergebnis fest, das sie erzeugt. Verwende für die Preisfunktion, die ihre Schleife bei Index 1 beginnt, [4, 6, 10]. Die erwartete Summe ist 20; die tatsächliche Summe ist 16. Anhand dieser konkreten Werte kannst du prüfen, ob sich jede Untersuchung noch auf denselben Fehler bezieht.

Die Differenz beträgt 4 und das tatsächliche Ergebnis ist gleich 6 + 10. Eine konkrete Hypothese lautet, dass der erste Preis übersprungen wird. Diese Hypothese sagt etwas voraus, das du überprüfen kannst: Die Schleife wird Index 0 nie besuchen.

Sechs Schritte befolgen
  1. Reproduzieren: Finde eine Eingabe, die den Fehler zuverlässig zeigt.
  2. Erwartetes und tatsächliches Ergebnis nennen: Berechne das erwartete Ergebnis unabhängig.
  3. Eine Hypothese aufstellen: Nenne eine mögliche Ursache und das daraus erwartete Verhalten.
  4. Sie prüfen: Untersuche Werte mit Ausgaben, einer Ablauftabelle oder einem Debugger.
  5. Die Ursache beheben: Nimm eine gezielte Änderung vor.
  6. Erneut testen: Führe die fehlschlagende Eingabe und zuvor funktionierende Fälle aus.

Gib den Index innerhalb der Schleife aus. Für diese Eingabe sind die einzigen Indizes 1 und 2, was die Vorhersage bestätigt. Wenn range bei 0 beginnt, wird das übersprungene Element berücksichtigt. Durchläufst du die Preise direkt, musst du keinen Index verwalten:

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

Die korrigierte Funktion gibt 20 für [4, 6, 10], 5 für [5] und 0 für [] zurück. Der Fall mit einem Element ist nützlich, weil die fehlerhafte Schleife dafür zuvor 0 zurückgab.

Zu jedem Ergebnis 4 zu addieren würde die beobachtete Summe korrigieren, aber die Ursache bestehen lassen. Für [5] würde diese Behelfslösung 4 zurückgeben; der fehlende Betrag hängt von der Eingabe ab. Prüfe, ob eine vorgeschlagene Korrektur alle Belege erklärt, bevor du sie beibehältst.

Eine größere Suche eingrenzen

Bei Teile und herrsche prüfst du an einer Stelle während der Ausführung die Werte, von denen das falsche Ergebnis abhängt. Ist ein benötigter Wert bereits falsch, untersuche den früheren Code, der ihn erzeugt hat. Sind die benötigten Werte noch richtig, verfolge ihre spätere Verarbeitung. Wiederhole das innerhalb des verbleibenden Abschnitts.

Du kannst auch eine Funktion einzeln aufrufen oder vorübergehend nicht zugehörigen Code entfernen. Ein minimales reproduzierbares Beispiel enthält den kürzesten Code und die kleinste Eingabe, die noch fehlschlagen. Trat ein Problem zuerst bei Hunderten von Datensätzen auf, erleichtert es jede Untersuchung, einen oder zwei auslösende Datensätze zu finden.

Prüfen, was die Daten tatsächlich sind

Eine angezeigte 5 kann die Zeichenkette "5" sein. "5" + "3" ergibt "53", während die Addition von Zahlen 8 ergibt. Untersuche type(value), um den Datentyp zu prüfen. Verwende repr(value), um Leerzeichen und Zeilenumbruchzeichen sichtbar zu machen, die eine gewöhnliche Ausgabe verbergen kann, wie in ' Ada'.

Erkläre den Code laut, Zeile für Zeile, einschließlich der Frage, was jede Schleife tatsächlich durchläuft und was jede Funktion zurückgibt. Das ist Fehlersuche mit einer Gummiente: Einen Schritt zu erklären, deckt oft die Lücke zwischen der beabsichtigten und der geschriebenen Operation auf.

Ändere jeweils nur eine Ursache, damit du das Ergebnis mit der Änderung in Verbindung bringen kannst. Teste sowohl die zuvor funktionierenden Fälle als auch den fehlgeschlagenen Fall erneut.

Wichtige Erkenntnisse

  • Reproduziere den Programmfehler und halte erwartetes und tatsächliches Ergebnis fest, bevor du etwas änderst.
  • Eine hilfreiche Hypothese sagt etwas voraus, das du überprüfen kannst.
  • Behebe die Ursache mit einer Änderung und teste dann fehlgeschlagene und zuvor funktionierende Fälle erneut.
  • Verwende ein minimales Beispiel oder Zwischenwerte, um die Suche einzugrenzen.
  • Prüfe Datentypen und verborgene Zeichen, wenn Werte irreführend aussehen.

3.2 Wertänderungen mit Ausgaben und einem Debugger beobachten

Die endgültige Antwort eines Programms verbirgt den Weg, auf dem sie entstanden ist. Vorübergehende Ausgaben, eine Ablauftabelle und ein Debugger lassen dich diesen Weg sehen und eine konkrete Hypothese dazu prüfen, wo etwas schiefgeht.

Einen Wert zu einem bekannten Zeitpunkt ausgeben

Beschrifte diagnostische Ausgaben, damit die Bedeutung einer Zahl klar ist. Python 3.8 und spätere Versionen unterstützen diese f-String-Form:

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

Setze sie bei der fehlerhaften Preisschleife unmittelbar vor total += prices[i]. Mit den Preisen [4, 6, 10] gibt sie aus:

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

Dies sind die Summen vor jeder Addition. Nach der ersten Ausgabe addiert die Schleife 6; nach der zweiten addiert sie 10. Eine Ausgabe nach der Addition würde andere Summen zeigen. Entscheide vor der Deutung der Ausgabe, welcher Zeitpunkt deine Frage beantwortet.

Denselben Code von Hand nachvollziehen

Eine Ablauftabelle hält Variablen Schritt für Schritt fest. Für diese Schleife:

Index iAddierter PreisSumme vorherSumme nachher
1606
210616

Es gibt keinen Schleifendurchlauf für Index 0. Folge den tatsächlich im Code angegebenen Start- und Endwerten, auch wenn du bereits weißt, was die Schleife tun sollte. Eine Tabelle hilft, deine Erwartung vom tatsächlichen Geschehen zu unterscheiden.

An einem Haltepunkt pausieren

Ein Debugger hält ein laufendes Programm an, damit du seinen aktuellen Zustand untersuchen kannst. Ein Haltepunkt markiert eine Stelle, an der pausiert werden soll. Klicke in Editoren wie Thonny und VS Code neben eine Zeilennummer und starte den Debug-Modus; klicke in IDLE mit der rechten Maustaste auf die Zeile und wähle Set Breakpoint.

Wähle nach dem Anhalten einen Schritt passend zu der Frage, die du untersuchst:

BefehlWirkung
ProzedurschrittFührt die aktuelle Zeile einschließlich einer aufgerufenen Funktion aus
EinzelschrittSteigt in eine Funktion ein, die in dieser Zeile aufgerufen wird
Funktion verlassenFührt diese Funktion zu Ende und pausiert nach der Rückkehr
FortsetzenFührt das Programm bis zu einem weiteren Haltepunkt oder bis zum Ende aus

Übergibt der aufrufende Code korrekte Argumente, erhält aber eine falsche Antwort, steige in die Funktion ein. Musst du nur das zurückgegebene Ergebnis sehen, führe den Aufruf als Prozedurschritt aus. Untersuche die Werte vor und nach der Zeile, die den Fehler erzeugen könnte.

Pythons textbasierten Debugger verwenden

Füge breakpoint() unmittelbar vor dem Code ein, den du untersuchen möchtest. Bei der Standardkonfiguration des Debuggers startet die Ausführung des Programms an dieser Stelle pdb. Gib diese Befehle an seiner Eingabeaufforderung (Pdb) ein:

  • p total zeigt total an.
  • n führt die nächste Zeile als Prozedurschritt aus.
  • s steigt in einen Funktionsaufruf ein.
  • c setzt die Ausführung fort.
  • q beendet die Fehlersuche.

Das sind Debugger-Befehle, keine Zeilen zum Kopieren in dein Programm.

Ausgegebene Werte von Rückgabewerten unterscheiden

Eine Funktion kann die richtige Zahl ausgeben und dennoch None zurückgeben, weil ihr return total fehlt. Untersuche den Wert, den der aufrufende Code erhält, wenn der Fehler nach dem Funktionsaufruf auftritt. Eine korrekte Ausgabe innerhalb der Funktion belegt nicht, dass der aufrufende Code diese Zahl erhalten hat.

Verwende Ausgaben für schnelle Hinweise über mehrere Schleifendurchläufe hinweg und den Debugger, um einen bestimmten Zeitpunkt zu untersuchen. Entferne nach der Fehlerbehebung vorübergehende Ausgaben und breakpoint()-Aufrufe, damit das fertige Programm normal läuft.

Wichtige Erkenntnisse

  • Beschrifte Ausgaben zur Fehlersuche und beachte, ob sie vor oder nach einer Aktualisierung erfolgen.
  • Eine Ablauftabelle verfolgt tatsächliche Variablenänderungen Schritt für Schritt.
  • Haltepunkte pausieren die Ausführung; Schrittbefehle steuern, wie viel Code als Nächstes ausgeführt wird.
  • breakpoint() öffnet standardmäßig pdb; p, n, s, c und q sind Debugger-Befehle.
  • Untersuche Rückgabewerte, wenn eine Funktion korrekt ausgibt, aber der aufrufende Code fehlschlägt.
  • Entferne vorübergehende diagnostische Ausgaben und Haltepunkte nach der Korrektur.
4

Deine Funktionen mit Tests prüfen

Mit automatisierten Prüfungen kannst du ein nützliches Beispiel jedes Mal wiederholen, wenn sich eine Funktion ändert. Du schreibst Zusicherungen mit klaren Erwartungen, wählst Eingaben an den Grenzen einer Regel und verhinderst, dass Tests die Anwendung starten, die sie importieren. Das Standardframework unittest gibt dann jedem Test einen Namen und ein eigenes Ergebnis. Das Lesen von fehlgeschlagenen Tests und Testfehlern verbindet das Testen mit der Fehlersuche: Der Test reproduziert ein Problem und die Untersuchung findet seine Ursache.

4.1 Prüfungen schreiben, die bei falscher Annahme fehlschlagen

Eine Zusicherung hält etwas fest, das wahr sein muss, wenn dein Code korrekt funktioniert. Sie kann einen Programmfehler nahe an seiner Entstehungsstelle stoppen oder das Ergebnis einer Funktion mit dem erwarteten Wert vergleichen.

Eine Bedingung und eine optionale Meldung schreiben
assert letter_grade(90) == "A", "90 should be an A"

Python wertet die Bedingung aus. Gibt letter_grade(90) den Wert "A" zurück, ist die Bedingung wahr und die Ausführung läuft ohne Ausgabe weiter. Gibt die Funktion "B" zurück, löst Python AssertionError mit der Meldung 90 should be an A aus. Der Traceback zeigt auf die fehlgeschlagene Prüfung.

Auch ohne die Meldung prüft assert letter_grade(90) == "A" das Ergebnis. Die letzte Ausnahmezeile enthält AssertionError, während der Traceback den Ausdruck zeigt. Eine hilfreiche Meldung nennt die Erwartung, die nicht erfüllt wurde; sie sollte dir helfen, die geprüfte Regel zu finden.

Einen internen Fehler früh stoppen

Angenommen, eine interne Berechnung benötigt eine nicht leere Liste:

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

Eine leere Liste löst nun vor der Division die Zusicherung aus. Die Prüfung dokumentiert die interne Annahme der Funktion und zeigt direkt auf deren Verletzung. Sie gibt einer leeren Liste weder ein arithmetisches Mittel noch entscheidet sie, wie eine Anwendung auf fehlende Benutzerdaten reagieren soll.

Die Eingabevalidierung aktiv halten

Pythons Option -O entfernt assert-Anweisungen. Ein Programm, das sich beim Zurückweisen externer Eingaben auf eine Zusicherung verlässt, kann sich daher bei optimierter Ausführung anders verhalten. Prüfe Benutzereingaben und andere externe Daten mit gewöhnlicher Ablaufsteuerung:

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

Hier meldet raise ValueError(...) einen ungeeigneten Wert. Die if-Anweisung wird auch mit -O ausgeführt. Wähle eine Zusicherung für eine interne Annahme über das Programm und eine aktive Eingabeprüfung für Daten, die von außen fehlerhaft eingegeben werden können.

Eine Prüfung vermeiden, die nie fehlschlagen kann

assert ist eine Anweisung, keine Funktion. Schreibe die Bedingung und die Meldung durch ein Komma getrennt:

assert x > 10, "x too small"

assert (x > 10, "x too small") erzeugt ein Tupel mit zwei Elementen. Ein nicht leeres Tupel ist auch dann wahr, wenn sein erstes Element False ist, sodass die Zusicherung besteht. Python kann davor warnen, dass diese Zusicherung immer wahr ist. Klammern um die Bedingung allein, wie in assert (x > 10), erzeugen dieses Tupel nicht; das Komma innerhalb der Klammern ist das Problem.

Verwende == für den Vergleich. assert total = 20 ist ungültige Syntax, weil = einen Wert zuweist.

Zahlen mit der beabsichtigten Genauigkeit vergleichen

Verwende für eine berechnete Gleitkommazahl eine Prüfung auf annähernde Gleichheit:

import math

assert math.isclose(0.1 + 0.2, 0.3)

Ein exakter Vergleich schlägt hier fehl, weil sich die gespeicherte Gleitkommasumme geringfügig von 0.3 unterscheidet. Ein einfacher automatisierter Test wendet dieselbe Idee einer Zusicherung auf eine Funktion an: assert total_price([4, 6, 10]) == 20. Der erwartete Wert ergibt sich aus der Regel der Funktion, sodass die Prüfung eine falsche Implementierung aufdecken kann.

Wichtige Erkenntnisse

  • assert condition, message löst AssertionError aus, wenn die Bedingung falsch ist.
  • Zusicherungen können interne Annahmen und erwartete Funktionsergebnisse prüfen.
  • Verwende für externe Eingaben if und eine Fehlermeldung oder Ausnahme; -O entfernt Zusicherungen.
  • Ein Komma innerhalb von assert (condition, message) erzeugt ein als wahr ausgewertetes Tupel.
  • Verwende == für Gleichheit und math.isclose für den Vergleich berechneter Gleitkommazahlen.

4.2 Tests auswählen, die einen Programmfehler aufdecken können

Ein Unit-Test prüft eine kleine Codeeinheit, meist eine Funktion, mit einer gewählten Eingabe und einem erwarteten Ergebnis. Automatisierte Tests machen es leicht, dieselben Prüfungen nach Änderungen zu wiederholen. So helfen sie, erneut auftretende Fehler in zuvor funktionierendem Verhalten zu erkennen.

Mit der Spezifikation beginnen

Angenommen, eine Bewertungsfunktion muss für Punktzahlen ab 90 "A", für Punktzahlen ab 80 bis unter 90 "B" und unter 80 "C" zurückgeben. Die fehlerhafte erste Bedingung lautet score > 90.

Tests sollten mehrere Aufgaben erfüllen:

  • Typische Fälle prüfen gewöhnliche Eingaben innerhalb jedes Bereichs, etwa 95 und 85.
  • Grenzwertfälle prüfen die Werte, an denen eine Regel wechselt, etwa 90 und 89 oder 80 und 79.
  • Randfälle prüfen Eingaben wie null oder eine leere Sammlung, wenn die Regeln der Funktion diese zulassen.

Ermittle die erwartete Antwort anhand dieser Regeln. Übernimmst du die aktuelle Antwort des Programms in einen Test, kann dessen Fehler erhalten bleiben.

Die Tests neben das Modul legen

Speichere die Tests in test_grade.py und die Funktion in grade.py. Der Anwendungsstart in grade.py gehört unter den __main__-Schutz, damit der Import der Funktion das Programm nicht startet.

from grade import letter_grade

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

Bei der fehlerhaften Regel besteht die erste Zusicherung. Die zweite schlägt fehl, weil 90 nicht größer als 90 ist; die Ausführung stoppt dort, vor der dritten Zusicherung in dieser Funktion. Die Änderung der ersten Bedingung zu score >= 90 korrigiert diesen Grenzfall. Führe alle Tests erneut aus, um den betroffenen Fall und das frühere Verhalten zu prüfen.

Sicherstellen, dass die Tests tatsächlich laufen

Eine Testfunktion zu definieren, ruft sie nicht auf. Wenn du kein Testwerkzeug zum Ausführen verwendest, ergänze test_letter_grade() am Ende der Testdatei und führe dann python test_grade.py aus. Um pytest zu verwenden, installiere es mit python -m pip install pytest und führe dann pytest test_grade.py im Terminal aus. Es findet die Testfunktionen und meldet ihre Ergebnisse. Verzichte auf manuelle Aufrufe, wenn ein Testwerkzeug die Ausführung übernimmt.

Ein Test, der lediglich letter_grade(90) aufruft, enthält keinen Vergleich. Er kann erfolgreich enden, obwohl die zurückgegebene Antwort falsch ist; er schlägt nur fehl, wenn der Aufruf eine unerwartete Ausnahme auslöst. Eine Zusicherung verbindet den Aufruf mit dem geforderten Verhalten.

Rückgabewerte und Eigenschaften zufälliger Ergebnisse testen

Eine Funktion, die eine Summe nur ausgibt, gibt None zurück. Ein Vergleich wie assert print_total([4, 6]) == 10 schlägt daher auch dann fehl, wenn auf dem Bildschirm 10 erscheint. Lass die Berechnung ihr Ergebnis zurückgeben und überlasse main die Ausgabe.

Zufällige Ergebnisse brauchen eine andere Erwartung. Von einer Würfelfunktion ohne festgelegten Startwert kann nicht verlangt werden, bei jedem Aufruf genau dieselbe Augenzahl zurückzugeben. Prüfe, ob jeder von 100 Aufrufen einen zulässigen Wert von 1 bis einschließlich 6 zurückgibt, oder lege vor einer reproduzierbaren Folge einen Startwert fest. Besteht der Test der Schranken, sind die Schranken für diese Aufrufe geprüft; er belegt nicht, dass jede Augenzahl gleich wahrscheinlich ist.

Wenn ein neuer Programmfehler auftritt, ergänze vor der Korrektur der Funktion einen Test, der wegen dieses Fehlers fehlschlägt. Behalte diesen Regressionstest, damit spätere Änderungen dasselbe Verhalten erneut prüfen. Bestandene Tests zeigen, was bei den getesteten Fällen geschah; weitere Eingaben können dennoch einen anderen Fehler aufdecken.

Wichtige Erkenntnisse

  • Leite erwartete Ergebnisse unabhängig von der Implementierung aus der Spezifikation ab.
  • Teste gewöhnliche Eingaben, Regelgrenzen und relevante Randfälle.
  • Testfunktionen brauchen einen Aufruf oder ein Testwerkzeug zur Ausführung; Definitionen allein führen keine Prüfungen durch.
  • Zusicherungen müssen Rückgabewerte mit dem beabsichtigten Verhalten vergleichen.
  • Teste geeignete Eigenschaften zufälliger Ausgaben oder richte eine reproduzierbare Folge ein.
  • Behalte für jeden neu gefundenen Programmfehler einen Test, um Regressionen zu erkennen.

4.3 Eine unittest-Testdatei ausführen und auswerten

Python enthält unittest, ein Testframework, das Tests findet, ausführt und einzelne Ergebnisse meldet. Es muss nicht mit pip installiert werden. Seine Klassenstruktur kannst du als Vorlage verwenden, während du das Testen von Funktionen lernst.

Unabhängige Testmethoden schreiben

Schreibe für eine Funktion in grade.py Folgendes 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 erbt die Testwerkzeuge von unittest.TestCase. Jeder Test ist eine Methode, deren Name mit test beginnt. self bezeichnet das aktuelle Testobjekt; belasse es in der Parameterliste jeder Methode und vor Aufrufen von Zusicherungsmethoden. Du kannst diese Struktur kopieren, ohne eigene Klassen zu entwerfen.

Tests laufen standardmäßig in alphabetischer Reihenfolge ihrer Methodennamen, also kommt test_boundary vor test_low und test_top. Sorge dafür, dass jeder Test seine benötigte Eingabe selbst bereitstellt und unabhängig von vorherigen Tests funktioniert.

Eine Zusicherungsmethode auswählen
MethodePrüfung
self.assertEqual(actual, expected)Werte sind gleich
self.assertNotEqual(a, b)Werte unterscheiden sich
self.assertTrue(condition)Eine Bedingung ist wahr
self.assertFalse(condition)Eine Bedingung ist falsch
self.assertIn(item, collection)Das Element gehört zur Sammlung
self.assertAlmostEqual(a, b)Die Differenz ergibt standardmäßig auf 7 Nachkommastellen gerundet null

Bevorzuge beim Vergleich von Werten assertEqual(a, b) gegenüber assertTrue(a == b): Der Bericht über einen Fehlschlag zeigt die beiden Werte. Die unittest-Methoden behalten ihre Prüfungen auch bei, wenn Python mit -O läuft.

Um eine erwartete Ausnahme zu prüfen, setze den Aufruf in assertRaises:

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

Dieser Test setzt voraus, dass die Regel der Funktion diese Punktzahl mit ValueError zurückweist. Eine Rückgabe ohne Ausnahme lässt die Prüfung fehlschlagen; eine andere Ausnahme als ein Zusicherungsfehler ist ein Testfehler.

Den Bericht ausführen und lesen

Führe python test_grade.py aus, um das geschützte unittest.main() der Datei auszuführen. Oder führe python -m unittest aus, um test*.py-Dateien im aktuellen Ordner zu finden. python -m unittest -v gibt einzelne Testnamen und ihre Ergebnisse aus.

Im Kurzbericht bedeutet . bestanden, F bedeutet, dass eine Zusicherung fehlgeschlagen ist, und E bedeutet, dass eine andere Ausnahme aufgetreten ist. Bei einer Bewertungsfunktion mit score > 90 erzeugen die drei obigen Tests F... Der Bericht zum fehlgeschlagenen Test test_boundary zeigt 'B' != 'A': Das tatsächliche Ergebnis ist "B", während das erwartete Ergebnis "A" ist. Die Zusammenfassung meldet drei Tests und einen fehlgeschlagenen Test.

Prüfe vor einer Änderung der Funktion die Erwartung des Tests anhand der Bewertungsregeln. Eine falsche Erwartung erfordert eine Korrektur des Tests. Laufen keine Tests, prüfe die Methodennamen, den Schutz für die direkte Ausführung und den Startbefehl. Vermeide außerdem, deine Datei unittest.py zu nennen, da sie das Standardmodul verdeckt.

Wichtige Erkenntnisse

  • Setze test-Methoden in eine Klasse, die von unittest.TestCase erbt.
  • Verwende self.assertEqual und andere Zusicherungsmethoden für klare Prüfungen und Berichte.
  • assertRaises prüft eine erwartete Ausnahme; für Vergleiche von Gleitkommazahlen kannst du assertAlmostEqual verwenden.
  • Führe eine geschützte Testdatei direkt aus oder verwende python -m unittest zur automatischen Testerkennung.
  • Lies F als fehlgeschlagene Zusicherung und E als andere Ausnahme.
  • Prüfe einen fehlgeschlagenen Test anhand der Spezifikation, bevor du die Funktion änderst.
  • Jeder Test muss unabhängig von der alphabetischen Ausführungsreihenfolge laufen.

Python-Module, Fehlersuche und Tests: Beispiele

4 Interaktive Lektionen

1

Ein Programm aus wiederverwendbaren Teilen erstellen

20 Schritte
Wähle Importe und Bibliotheksfunktionen, verwende eigenen Code wieder und verbinde installierte Pakete mit dem Python, das sie ausführt.
  1. 1
    EinführungMit wiederverwendbarem Code beginnen

    Ein Programm kann Code aus Pythons Standardbibliothek, einer anderen selbst geschriebenen Datei oder einem installierten Paket aufrufen. Die erste Frage ist, welcher Name dem Programm nach dem Import zur Verfügung steht.

    Du verfolgst eine Berechnung vom Import bis zum Rückgabewert, richtest dann ein wiederverwendbares Modul ein und verbindest eine Paketinstallation mit ihrem Interpreter. Prüfe dabei, ob ein Ergebnis ein Wert ist, den du behältst, oder eine Änderung an einer vorhandenen Liste.

  2. 2
    ErklärungDer Import bestimmt die Art des Aufrufs

    Diese Importe stellen dieselbe Funktion über unterschiedliche Bindungen bereit:

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

    Beide geben 4.0 aus. Der erste erzeugt math, daher verwendet der Aufruf einen Punkt. Der zweite erzeugt sqrt, daher braucht der Aufruf keinen vorangestellten Modulnamen. Eine falsche Aufrufart löst NameError aus, wenn der betreffende Name nicht gebunden wurde.

  3. 3
    BeispielDie Hypotenuse berechnen

    Mit import math kann ein rechtwinkliges Dreieck mit den Seitenlängen 3 und 4 so berechnet werden:

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

    Die Quadrate sind 9 und 16. Ihre Summe ist 25 und math.sqrt(25) gibt 5.0 zurück. Python wertet das Argument aus, bevor es die Funktion aufruft.

    Der vorangestellte Modulname zeigt Lesenden auch, woher sqrt stammt. Ein Wildcard-Import verbirgt diese Herkunft und kann vorhandene Namen ersetzen, etwa eine Variable namens e.

  4. 4
    HerausforderungDie Aliasbindung nachvollziehen

    Ein neues Skript führt diese Zeilen aus. Was geschieht in der letzten Zeile und wie lässt sich der Fehler beheben?

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

    ---reveal---

    Es löst NameError aus, weil der Import st bindet, nicht statistics. Verwende st.mean([4, 8, 12]); der Aufruf gibt 8 zurück. Ein Alias wählt die Bindung in diesem Programm aus; er erzeugt nicht zusätzlich den ursprünglichen Modulnamen.

  5. 5
    BeispielFür genügend ganze Behälter runden

    Eine Wand von 23 Quadratmetern soll gestrichen werden. Jede Dose reicht für 10 Quadratmeter.

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

    Die Division ergibt 2.3; ceil ergibt 3, also genügend ganze Dosen. round(2.3) ergibt nur 2.

    Bei negativen Eingaben bedeutet abwärts weiterhin in Richtung minus unendlich: math.floor(-2.5) ist -3, während int(-2.5) in Richtung null abschneidet und -2 ergibt.

  6. 6
    KernaussageDen Vergleich an die Zahl anpassen

    Berechnete Gleitkommazahlen können geringfügig von den dezimal dargestellten Zielwerten abweichen:

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

    Verwende für diesen näherungsweisen Vergleich eine Prüfung auf annähernde Gleichheit. Unabhängig davon sind die zulässigen Eingaben einer Funktion weiterhin wichtig: math.sqrt(-1) löst ValueError aus.

    Das eingebaute round braucht keinen Import. Bei einem Wert genau in der Mitte wählt es die benachbarte gerade Zahl: round(2.5) ist 2 und round(3.5) ist 4.

  7. 7
    ErklärungDas benötigte Zufallsergebnis auswählen

    Wähle nach import random einen Aufruf nach seiner Aufgabe:

    • randint(1, 6) wählt eine ganze Zahl einschließlich 6.
    • randrange(1, 6) wählt eine ganze Zahl unter Ausschluss von 6.
    • random() liefert eine Gleitkommazahl ab 0,0 bis ausschließlich 1,0.
    • choice(items) wählt ein Element.
    • sample(items, k) wählt k Positionen ohne Zurücklegen.

    Zwei ausgewählte Positionen können denselben Wert enthalten. Wenn bei [1, 1] beide Positionen gezogen werden, erscheint daher die 1 mehrfach.

  8. 8
    HerausforderungDie gemischte Liste behalten

    Welchen Wert enthält names am Ende und wie sollte die letzte Zeile geändert werden, damit die Liste erhalten bleibt?

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

    ---reveal---

    Die Variable enthält None. shuffle verändert die vorhandene Liste und gibt dann None zurück; die Zuweisung ersetzt die Bindung an die Liste durch diesen Rückgabewert. Verwende random.shuffle(names) in einer eigenen Zeile. Die neue Reihenfolge der Liste ist zufällig, aber das Rückgabeverhalten ist festgelegt.

  9. 9
    VerbindungEine Simulation wiederholen und weitere Werkzeuge finden

    Rufe vor dem Erzeugen von Werten random.seed(42) auf, um bei derselben Python-Version dieselbe Folge zu wiederholen. Das erleichtert es, einen zufällig auftretenden Fehler zu reproduzieren. Verwende secrets für Sicherheitstoken.

    Andere Standardmodule lösen alltägliche Aufgaben: statistics.mean([2, 4, 9]) ergibt 5 und median ergibt 4. datetime.date.today() liefert das heutige Datum. sys.argv listet den Namen des ausgeführten Skripts gefolgt von seinen Befehlszeilenargumenten auf.

  10. 10
    BeispielEine wiederverwendbare Funktion in ein Modul setzen

    Speichere dies als geometry.py:

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

    Ein Skript im selben Ordner kann import geometry und danach print(geometry.circle_area(2)) ausführen. Es gibt 12.566370614359172 aus.

    Importiere die Datei ohne .py. Die erste Zeichenkette der Funktion ist ihr Docstring, den help(geometry.circle_area) anzeigen kann.

  11. 11
    ErklärungEin Import führt Anweisungen auf Modulebene aus

    Angenommen, geometry.py endet außerhalb einer Funktion mit print(circle_area(2)). Sein erster Import gibt den Flächeninhalt als Nebeneffekt aus.

    Python führt Anweisungen auf Modulebene der Reihe nach aus. Die Definition von circle_area erstellt die Funktion, ohne ihren Körper auszuführen; ihr Aufruf innerhalb der Ausgabe auf Modulebene führt die Berechnung aus. Ein zweiter Import im selben Prozess verwendet das geladene Modul wieder. Auch eine interaktive Shell behält nach einer Änderung der Datei diese geladene Version, bis du sie neu startest.

  12. 12
    BeispielNur bei direkter Ausführung starten

    Belasse die wiederverwendbare Funktion oberhalb dieses Blocks:

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

    Eine direkte Ausführung setzt __name__ auf "__main__", sodass main() ausgeführt wird. Ein Import setzt es auf "geometry", sodass der Start übersprungen wird.

    Die Definitionen bleiben in beiden Fällen verfügbar. Dadurch kann ein Test circle_area importieren, ohne die gewöhnliche Ausgabe des Programms zu erzeugen.

  13. 13
    HerausforderungDie Funktion für importierenden Code verfügbar halten

    Eine Datei definiert convert innerhalb ihres if __name__ == "__main__":-Blocks. Ein neuer Testprozess importiert die Datei und kann convert nicht finden. Welche Anordnung ermöglicht sowohl die Wiederverwendung als auch den Start bei direkter Ausführung?

    ---reveal---

    Verschiebe def convert(...) außerhalb der Schutzbedingung und belasse nur den Programmstart innerhalb. Beim Import ist die Schutzbedingung falsch, sodass eine Definition darin übersprungen wird. Durch das Verschieben der Definition wird sie verfügbar, ohne die Anwendung zu starten.

  14. 14
    TippDie Datei prüfen, die ein Import findet

    Python prüft eingebaute Module und durchsucht dann sys.path der Reihe nach. Der Ordner des Skripts steht normalerweise vor Bibliotheksordnern. Eine lokale Datei random.py kann daher das random verdecken, das du importieren wolltest.

    Benenne diese Datei zum Beispiel in dice.py um. Verwende für eigene Hilfsmodule gültige Namen wie my_tools.py und bewahre sie neben dem Anfängerskript auf, das sie importiert. Eine Datei außerhalb des Suchpfads wird durch einen gewöhnlichen Import nicht gefunden.

  15. 15
    BeispielIm Terminal installieren, in Python importieren

    Führe im Terminal aus:

    python -m pip install cowsay
    

    Danach kann Python-Code Folgendes verwenden:

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

    Das Paket gibt eine Kuh aus Textzeichen und eine Sprechblase aus. pip installiert Code, während import die Bindung erzeugt, die dein Programm verwendet. Der Installationsbefehl ist keine Python-Anweisung; an einer >>>-Eingabeaufforderung führt er zu ungültiger Syntax.

  16. 16
    ErklärungDas pip des ausführenden Python verwenden

    Läuft ein Skript mit python3, installiere über denselben Befehl:

    python3 -m pip install cowsay
    python3 game.py
    

    -m pip wählt das pip, das zu diesem Interpreter gehört. Unter Windows kann dein Befehl stattdessen py sein.

    Kann der Editor ein erfolgreich installiertes Paket nicht importieren, vergleiche den dort ausgewählten Interpreter mit dem im Terminal verwendeten. Eine erfolgreiche Installation in einem Python installiert das Paket nicht in jedem anderen Python.

  17. 17
    HerausforderungInstallationsnamen und Importnamen unterscheiden

    Die Dokumentation eines Pakets empfiehlt, Pillow zu installieren und PIL zu importieren. Die Installation für dein ausführendes Python gelingt, aber import Pillow schlägt fehl. Was sollte sich ändern und warum?

    ---reveal---

    Verwende import PIL. Der von pip verwendete Distributionsname kann sich von dem bereitgestellten Python-Importnamen unterscheiden. Da bereits feststeht, dass der Interpreter passt, würde die Wiederholung des unveränderten Installationsbefehls diesen konkreten Namensfehler bestehen lassen.

  18. 18
    TippEin Paket untersuchen, bevor du es änderst

    python -m pip list zeigt installierte Versionen. show requests liefert Version und Speicherort eines Pakets; install --upgrade requests aktualisiert es und uninstall requests entfernt es. Jeder kurze Befehl folgt auf python -m pip.

    Prüfe vor der Installation den genauen PyPI-Namen und die Projektdokumentation. Verwende bei einem Fehler externally-managed-environment eine virtuelle Umgebung für das Projekt; erzwinge keine Installation mit sudo pip install.

  19. 19
    HerausforderungEinen Import und einen späteren Aufruf vorhersagen

    Ein neues Modul sizes.py enthält diesen Code. Ein anderes Skript führt from sizes import batches und dann print(batches(17)) aus. Was wird ausgegeben?

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

    ---reveal---

    Nur 4 wird ausgegeben. Der Import erstellt die Funktion, überspringt aber die geschützte Ausgabe. Der spätere Aufruf dividiert 17 durch 5 und rundet dann 3,4 auf 4 auf. Die Bindung math innerhalb von sizes steht dessen Funktion zur Verfügung.

  20. 20
    ZusammenfassungCode von seiner Quelle bis zum Aufruf verfolgen

    Wähle einen Import, der zu den Namen passt, die du verwenden möchtest. Prüfe, was ein Bibliotheksaufruf zurückgibt, einschließlich eines möglichen None bei einer Operation, die eine Liste verändert.

    Halte wiederverwendbare Definitionen beim Import verfügbar und setze den Anwendungsstart hinter den Hauptprogrammschutz. Stimme bei installiertem Code pip auf den ausführenden Interpreter ab und prüfe den dokumentierten Importnamen. Schlägt ein Aufruf fehl, helfen diese Einzelheiten, eine fehlende Bindung, ein fehlendes Attribut und eine fehlende Installation zu unterscheiden.

2

Einen Fehler bis zu seiner Ursache zurückverfolgen

11 Schritte
Lies Aufrufrahmen, erkenne häufige Ausnahmen und unterscheide einen Absturz von einem falschen Ergebnis ohne Fehlermeldung.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungDen Bericht als Beleg nutzen
  2. 2
    BeispielEine leere Liste erreicht eine Division
  3. 3
    ErklärungDen neuesten Aufrufrahmen finden
  4. 4
    BeispielDas Argument über die Aufrufer zurückverfolgen
  5. 5
    HerausforderungEin ungeeignetes Argument finden
  6. 6
    ErklärungGrammatik, Datentypen und Werte unterscheiden
  7. 7
    ErklärungUnterschiedliche Zugriffe führen zu unterschiedlichen Fehlern
  8. 8
    BeispielEin Programm kann mit einer falschen Summe normal enden
  9. 9
    HerausforderungEine fehlgeschlagene Addition erklären
  10. 10
    HerausforderungEinen Bibliotheksrahmen nutzen, ohne der Bibliothek die Schuld zu geben
  11. 11
    ZusammenfassungDie nächste Stelle zur Untersuchung auswählen
3

Einen Programmfehler vom Beleg bis zur Korrektur untersuchen

14 Schritte
Reproduziere eine falsche Summe, untersuche die Schleife, korrigiere sie gezielt und verfolge einen Funktionsaufruf mit Debugger-Befehlen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungDas falsche Ergebnis wiederholt erzeugen
  2. 2
    BeispielErwartetes und tatsächliches Ergebnis nennen
  3. 3
    ErklärungDie Vermutung überprüfbar machen
  4. 4
    BeispielVor der Aktualisierung ausgeben
  5. 5
    BeispielDie Additionen von Hand nachvollziehen
  6. 6
    HerausforderungEine Ausgabe nach der Aktualisierung deuten
  7. 7
    BeispielDas Durchlaufen selbst korrigieren
  8. 8
    VerbindungUnterschiedlich aufgebaute Eingaben erneut testen
  9. 9
    TippEinen größeren Fehlerfall verkleinern
  10. 10
    HerausforderungEinen Wert prüfen, der wie eine Zahl aussieht
  11. 11
    ErklärungBei dem Aufruf pausieren, den du untersuchen möchtest
  12. 12
    HerausforderungDen Schrittbefehl auswählen
  13. 13
    HerausforderungEine korrekte Ausgabe und eine falsche Rückgabe untersuchen
  14. 14
    ZusammenfassungDie Korrektur an Belege knüpfen
4

Aus einem Grenzwertfehler einen dauerhaften Test machen

16 Schritte
Schreibe Zusicherungen, wähle aufschlussreiche Eingaben und führe mit unittest unabhängige Prüfungen aus und deute ihre Ergebnisse.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungErwartetes Verhalten wiederholbar prüfen
  2. 2
    ErklärungEine Zusicherung hält eine Erwartung fest
  3. 3
    HerausforderungEine Prüfung finden, die nicht fehlschlagen kann
  4. 4
    KernaussagePrüfungen externer Eingaben aktiv halten
  5. 5
    BeispielEingaben um den Notenwechsel auswählen
  6. 6
    BeispielEine Testfunktion schreiben, die den Code importiert
  7. 7
    TippDie definierten Prüfungen ausführen
  8. 8
    HerausforderungEinen Schwellenwert korrigieren und die Prüfung behalten
  9. 9
    VerbindungDas zurückgegebene Ergebnis oder eine sinnvolle Eigenschaft testen
  10. 10
    BeispielDie unittest-Klassenvorlage verwenden
  11. 11
    ErklärungDie Zusicherung passend zum Ergebnis wählen
  12. 12
    BeispielEine fehlgeschlagene Notenprüfung lesen
  13. 13
    HerausforderungEinen fehlgeschlagenen Test von einem Testfehler unterscheiden
  14. 14
    TippPrüfen, was die automatische Testerkennung ausgeführt hat
  15. 15
    HerausforderungMit einem Bericht die Korrektur planen
  16. 16
    ZusammenfassungEinen Test für das korrigierte Verhalten behalten

Python-Module, Fehlersuche und Tests: Übungsaufgaben

40 Übungsfragen in 4 Sets

Set 1: Importe, Fehlerhinweise und erste Prüfungen10 Übungsfragen

Frage 1 von 10

Ein Skript enthält vor seiner Berechnung nur import math. Wie sollte es die Quadratwurzelfunktion für 81 aufrufen?
  1. sqrt(81)
  2. math(81).sqrt()
  3. math.sqrt(81)
  4. import.sqrt(81)
Antwort zeigenAntwort ausblenden
Antwort: C
Der Import erzeugt die Bindung math, sodass die Funktion über math.sqrt(81) erreicht wird und 9.0 zurückgibt. Der alleinstehende Aufruf sqrt(81) würde NameError auslösen, weil dieser Import keine separate Bindung für sqrt erzeugt hat.

Frage 2 von 10

Ein Shuttle fasst 8 Personen. Was gibt math.ceil(35 / 8) zurück und wofür steht das Ergebnis?
  1. 5, die für alle benötigten Shuttles
  2. 4, die für alle benötigten Shuttles
  3. 4.375, die zu buchenden Shuttles
  4. 4, die verbleibenden freien Plätze
Antwort zeigenAntwort ausblenden
Antwort: A
Die Division ergibt 4.375, sodass bei vier Shuttles drei Personen keinen Platz haben. ceil rundet auf die nächste ganze Zahl auf und ergibt fünf Shuttles. Das Runden auf die nächste ganze Zahl würde hier vier ergeben, benötigt werden aber genügend ganze Shuttles für alle.

Frage 3 von 10

Eine Datei namens text_tools.py definiert shorten. Wie kann eine andere Datei im selben Ordner die Funktion importieren und aufrufen?
  1. import text_tools.py, dann text_tools.shorten("Hello")
  2. import shorten, dann shorten.text_tools("Hello")
  3. import text_tools, dann shorten.text_tools("Hello")
  4. import text_tools, dann text_tools.shorten("Hello")
Antwort zeigenAntwort ausblenden
Antwort: D
Der Modulname einer Datei lässt die Endung .py weg, daher erzeugt import text_tools die Modulbindung. Über Punktnotation wird dann auf die Funktion shorten zugegriffen. Steht .py im Import, wird die Endung als Teil eines Importpfads statt als Dateiendung behandelt.

Frage 4 von 10

Du befindest dich an einer Python-Eingabeaufforderung >>> und gibst pip install cowsay ein. Warum meldet Python ungültige Syntax?
  1. Das Paket muss vor der Installation importiert werden.
  2. Der Installationsbefehl gehört in das Terminal.
  3. Der Paketname muss mit der Endung .py geschrieben werden.
  4. Der Installationsbefehl braucht eine Python-Zuweisung.
Antwort zeigenAntwort ausblenden
Antwort: B
Die Eingabeaufforderung >>> akzeptiert Python-Anweisungen, während die Installationssyntax von pip ein Terminalbefehl ist. Verlasse die Python-Shell und führe python -m pip install cowsay im Terminal aus. Ein vorheriger Import kann ein noch nicht installiertes Paket nicht verfügbar machen.

Frage 5 von 10

Ein Traceback endet mit ZeroDivisionError. Seine Aufrufrahmen zeigen von oben nach unten show([]), mean(data) und sum(values) / len(values). Welche Kette erklärt den Fehler am besten?
  1. Die Funktion show versuchte, ihren eigenen Namen durch null zu teilen.
  2. Eine leere Liste erreichte mean, wodurch der Divisor null wurde.
  3. Die Liste wurde leer, weil der Traceback rückwärts ausgegeben wird.
  4. Die Summe war null, was eine Division immer ungültig macht.
Antwort zeigenAntwort ausblenden
Antwort: B
Der neueste Aufrufrahmen dividiert durch len(values), und die früheren Aufrufe führen diesen Wert auf die leere Liste zurück. Ihre Länge ist null und verursacht die Ausnahme. Ein Zähler von null ist erlaubt, wenn der Divisor ungleich null ist, daher erklärt die Summe allein diesen Absturz nicht.

Frage 6 von 10

Welche Ausnahme löst int("7.25") aus?
  1. TypeError
  2. NameError
  3. IndexError
  4. ValueError
Antwort zeigenAntwort ausblenden
Antwort: D
Die Zeichenkette ist ein akzeptierter Eingabetyp für int, aber "7.25" ist kein Text in der Form einer ganzen Zahl, die diese Umwandlung verlangt. Deshalb entsteht ein ValueError. Ein TypeError würde auf einen ungeeigneten Eingabetyp oder eine ungeeignete Operation hinweisen, nicht auf diesen ungeeigneten Zeichenkettenwert.

Frage 7 von 10

Eine Funktion soll [9, 2, 5] zu 16 summieren, gibt aber 7 zurück. Du vermutest, dass sie das erste Element überspringt. Welche Beobachtung würde diese Idee am unmittelbarsten prüfen?
  1. Die besuchten Indizes der summierenden Schleife aufzeichnen.
  2. Die erwartete Summe nach dem Funktionsaufruf erneut ausgeben.
  3. Zum Ergebnis 9 addieren und nur dieselbe Eingabe prüfen.
  4. Die Summenvariable umbenennen und ohne Untersuchung erneut ausführen.
Antwort zeigenAntwort ausblenden
Antwort: A
Die Aufzeichnung der Indizes prüft die Vorhersage, dass Index 0 nie besucht wird. Erscheinen nur die Indizes 1 und 2, stützt das die Hypothese und weist auf die Schranken der Schleife hin. Die Addition von 9 korrigiert dieses Ergebnis, liefert aber keinen Beleg dafür, ob die Schleife andere Eingaben richtig verarbeitet.

Frage 8 von 10

Welche zwei Zeilen werden ausgegeben?

total = 0
for n in [3, 8]:
    print(f"{n=} {total=}")
    total += n
  1. n=3 total=3, dann n=8 total=11
  2. n=3 total=0, dann n=8 total=0
  3. n=3 total=0, dann n=8 total=3
  4. n=0 total=3, dann n=3 total=8
Antwort zeigenAntwort ausblenden
Antwort: C
Die Ausgabe erfolgt bei jedem Schleifendurchlauf vor der Addition. Sie zeigt zuerst die Anfangssumme 0 und dann die Summe 3 nach der ersten Addition. Die Summen 3 und 11 entsprächen einer Ausgabe nach jeder Aktualisierung; dort steht diese Ausgabe aber nicht.

Frage 9 von 10

Was geschieht bei normaler Ausführung dieses Codes?

count = 6
assert count < 5, "too many"
print("saved")
  1. Er löst AssertionError mit "too many" aus.
  2. Er gibt "saved" aus und meldet dann die Zusicherung.
  3. Er weist count den Wert 5 zu und läuft ohne Ausgabe weiter.
  4. Er gibt "too many" und danach "saved" aus.
Antwort zeigenAntwort ausblenden
Antwort: A
Die Bedingung 6 < 5 ist falsch, sodass die Zusicherung AssertionError mit der angegebenen Meldung auslöst. Die Ausführung stoppt vor der letzten Ausgabe, weil die Ausnahme unbehandelt ist. Die Meldung ist Teil der Ausnahme; sie ist keine gewöhnliche Ausgabe, nach der die Ausführung weiterläuft.

Frage 10 von 10

Die Regel lautet: bis einschließlich Gewicht 12 kostenlos, bei 13 bis einschließlich 18 eine Gebühr von 4 und über 18 eine Gebühr von 7. Tests für 5 und 20 bestehen. Welche Ergebnisse und welche Änderung diagnostizieren diesen Code richtig?

def fee(weight):
    if weight < 12:
        return 0
    if weight <= 18:
        return 4
    return 7
  1. Bei 12: 0; bei 18: 7. Ändere die zweite Prüfung zu < 18.
  2. Bei 12: 4; bei 18: 7. Ändere beide Vergleiche zu <.
  3. Bei 12: 0; bei 18: 4. Lass beide Vergleiche unverändert.
  4. Bei 12: 4; bei 18: 4. Ändere die erste Prüfung zu <= 12.
Antwort zeigenAntwort ausblenden
Antwort: D
Bei 12 ist die erste Bedingung falsch, sodass der zweite Zweig fälschlich 4 berechnet. Bei 18 berechnet dieser zweite Zweig korrekt 4. Wird 12 in den ersten Zweig eingeschlossen, ist die Grenze für die kostenlose Nutzung korrigiert; eine Änderung des zweiten Vergleichs würde einen weiteren Grenzwertfehler erzeugen. Die bestandenen Tests mit weiter entfernten Werten prüfen keine der beiden Grenzen.
Set 2: Module, Entscheidungen bei der Fehlersuche und Testergebnisse10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Nach import statistics as st lautet die nächste Zeile statistics.mean([3, 7]). Weitere Importe oder Zuweisungen gibt es nicht. Was erklärt den Fehler?
  1. Die Funktion mean benötigt außerdem import math.
  2. Nur st wurde gebunden; rufe st.mean([3, 7]) auf.
  3. Nur mean wurde gebunden; rufe mean([3, 7]) auf.
  4. Der Alias muss als statistics.mean(st) übergeben werden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Welchen Wert hat tickets nach diesem Code?

import random
tickets = [11, 22, 33]
tickets = random.shuffle(tickets)
  1. Eine neu gemischte Liste mit drei Elementen
  2. Das erste Element der gemischten Liste
  3. Die ursprüngliche Liste in ihrer ursprünglichen Reihenfolge
  4. None
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Hilfsmodul definiert double und enthält danach die ungeschützte Zeile print(double(6)). Ein anderes Skript importiert es während eines Laufs zweimal. Wie oft erzeugt diese Zeile eine Ausgabe?
  1. Einmal, beim ersten Import
  2. Zweimal, einmal pro import-Anweisung
  3. Nie, weil Importe nur Funktionsnamen lesen
  4. Einmal, nur wenn das Skript später double aufruft
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein Editor führt ein Skript mit Python A aus. Der Terminalbefehl python -m pip show cowsay meldet einen Speicherort in Python B, und der Editor kann cowsay nicht importieren. Was solltest du zuerst tun?
  1. Die pip-Installation von Python B unverändert wiederholen.
  2. Den Import durch den Ordnerpfad des Pakets ersetzen.
  3. Mit Python A -m pip install cowsay ausführen.
  4. Das Skript in das Bibliotheksverzeichnis von Python B verschieben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein Traceback hat drei Aufrufrahmen. Wo findest du zuerst den Ausnahmetyp und die Meldung?
  1. Im ersten Aufrufrahmen beim Skriptnamen
  2. In der Kopfzeile über dem ersten Aufrufrahmen
  3. In der Zeile mit dem ältesten Aufruf
  4. In der letzten Zeile unter den Aufrufrahmen
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Diese Funktion soll jede Zahl addieren. Welche Art von Problem erklärt das Ergebnis von total([2, 5, 8])?

def total(values):
    result = 0
    for i in range(1, len(values)):
        result += values[i]
    return result
  1. Ein IndexError tritt auf, weil die Schleife Index 3 erreicht.
  2. Ein Logikfehler ergibt 13, weil Index 0 übersprungen wird.
  3. Ein TypeError tritt auf, weil Listenelemente nicht addiert werden können.
  4. Ein Syntaxfehler tritt auf, weil range drei Argumente benötigt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ein fehlschlagendes Datenverarbeitungsprogramm hat 300 Zeilen und 200 Datensätze. Was macht ein nützliches minimales reproduzierbares Beispiel aus?
  1. Der vollständige Code mit jedem Datensatz und allen diagnostischen Ausgaben
  2. Die erwartete Antwort ohne die fehlschlagende Eingabe
  3. Der kürzeste Code und die kleinste Eingabe, die noch fehlschlagen
  4. Ein neu geschriebenes Programm mit bereits korrigierter Ausgabe
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Eingabeprüfung verwendet assert (score >= 0, "negative score"). Sie besteht, wenn score gleich -3 ist. Welche Änderung korrigiert die Prüfung und hält die Validierung zugleich unter -O aktiv?
  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
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine einfache Testdatei definiert test_discount mit zwei Zusicherungen, ruft die Funktion aber nie auf. Du führst die Datei mit python test_discount.py aus; Code zur Testausführung ist nicht vorhanden. Warum werden keine Zusicherungen geprüft?
  1. Python entfernt jede Zusicherung aus jeder test_-Datei.
  2. Jede Zusicherung muss über die Funktion verschoben werden.
  3. Die Definition der Funktion führt ihren Körper nicht aus.
  4. Die Testfunktion muss vor ihrem Aufruf True zurückgeben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine unittest-Methode ruft self.assertEqual(lookup("x"), 7) auf. Der Aufruf von lookup löst vor der Rückgabe unerwartet KeyError aus. Welches Kurzzeichen markiert diesen Test?
  1. F, weil jedes Problem in einem Test eine fehlgeschlagene Zusicherung ist
  2. E, weil eine andere Ausnahme die Prüfung unterbrochen hat
  3. ., weil kein Gleichheitsvergleich falsch ergeben hat
  4. F, weil KeyError dasselbe wie AssertionError ist
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Ursachen über Module und Tests hinweg verfolgen10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was gibt dieser Code aus?

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. Er löst TypeError aus, weil sqrt eine ganze Zahl ist.
  4. 4.0 4
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Eine Ziehung verwendet random.sample(["blue", "blue", "red"], 2). Warum kann das Ergebnis zwei Werte "blue" enthalten?
  1. Die Ziehung legt das erste Element vor der nächsten Ziehung immer zurück.
  2. Die beiden blauen Einträge stehen an unterschiedlichen Eingabepositionen.
  3. Der Wert 2 fordert zwei gleiche Kopien eines gewählten Elements an.
  4. Die Ziehung entfernt doppelte Werte erst nach ihrer Rückgabe.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Modul enthält diesen Code. Ein neuer Prozess importiert es und ruft dann helper.answer() auf. Was geschieht?

# helper.py
if __name__ == "__main__":
    def answer():
        return 42
  1. Es gibt 42 zurück, weil Python zuerst alle Definitionen lädt.
  2. NameError: Python definiert __name__ beim Import nie.
  3. AttributeError: Der Import hat die Funktionsdefinition übersprungen.
  4. Es gibt None zurück, weil der Schutz Rückgabewerte ändert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Ein Traceback beginnt mit deinem Aufruf run_report(), zeigt dann deinen Aufruf parse(raw) und endet mit ValueError innerhalb einer Umwandlung in einer Bibliothek. Du untersuchst raw bei deinem parse-Aufruf und findest "9x", obwohl die Regel Text in Form einer ganzen Zahl verlangt. Wo sollte die Untersuchung weitergehen?
  1. Verfolge, wo raw zu "9x" wurde, bevor parse aufgerufen wurde.
  2. Ersetze int(raw) durch int(raw[0]), damit diese Eingabe eine Zahl ergibt.
  3. Nimm den Bibliotheksrahmen als Fehlerbeweis und ändere deren Umwandlung.
  4. Lass die Eingabe unverändert und installiere die Bibliothek erneut, weil der Aufruf bereits lief.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Funktion gibt 18 aus, hat aber keine return-Anweisung. Ihr aufrufender Code wertet danach result + 2 aus, wobei result der Rückgabewert des Aufrufs ist. Warum tritt ein TypeError auf?
  1. result ist None, was nicht zu 2 addiert werden kann.
  2. result ist die Zeichenkette "18", weil Ausgaben Rückgaben umwandeln.
  3. result ist 18, aber die Addition zweier ganzer Zahlen ist hier ungültig.
  4. result ist undefiniert, weil jede Ausgabe seine Bindung löscht.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Eine Verarbeitungskette liest, konvertiert und summiert Daten. Bei einem reproduzierbaren Fehler sind die für die Summe benötigten Werte unmittelbar nach der Umwandlung bereits falsch. Das Einlesen allein liefert die erwarteten Rohwerte. Was ist die gezielteste nächste Untersuchung?
  1. Die endgültige Summe korrigieren und die Umwandlung unverändert lassen.
  2. Alle drei Stufen gemeinsam neu schreiben und nur die Endausgabe vergleichen.
  3. Die Umwandlung allein mit der kleinsten fehlschlagenden Roheingabe ausführen.
  4. Nur die letzte Ausgabe untersuchen, weil dort das falsche Ergebnis erscheint.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Ein Debugger ist bei answer = calculate(7) angehalten. Du möchtest die erste Zeile innerhalb von calculate untersuchen. Welchen Befehl solltest du verwenden?
  1. Prozedurschritt
  2. Einzelschritt
  3. Funktion verlassen
  4. Fortsetzen
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Die Regel besagt, dass eine Fahrt bis einschließlich Entfernung 6 kostenlos ist und bei einer Entfernung über 6 den Betrag 3 kostet. charge(6) gibt 3 zurück, aber der zugehörige Test erwartet 3 und besteht. Welche Änderung erzeugt einen nützlichen Regressionstest und korrigiert die Regel?
  1. Behalte bei 6 den Wert 3 und ergänze nur einen Test für eine weit entfernte kostenpflichtige Fahrt.
  2. Ändere die Regel so, dass 6 kostenpflichtig ist, und behalte den vorhandenen Test.
  3. Entferne die Prüfung bei 6 und vergleiche nur zwei bestandene Beispiele.
  4. Erwarte bei 6 den Wert 0, beobachte den Fehlschlag, korrigiere und teste erneut.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Eine unittest-Datei enthält test_alpha, der 4 erwartet, aber 5 erhält, einen bestandenen test_beta und test_gamma, der unerwartet TypeError auslöst. Welche kompakte Fortschrittszeichenkette ergibt die standardmäßige alphabetische Ausführung?
  1. E.F
  2. F.E
  3. F.F
  4. .FE
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein unittest.TestCase hat check_empty mit einer fehlschlagenden Gleichheitsprüfung und test_full mit einer bestandenen Prüfung. Das Testwerkzeug meldet einen Test und OK. Wie bringst du die fehlende Verhaltensprüfung zur Ausführung?
  1. Benenne check_empty in test_empty um und führe erneut aus.
  2. Füge return False am Ende von check_empty hinzu.
  3. Verschiebe check_empty in der Klasse unter test_full.
  4. Ersetze assertEqual in check_empty durch print.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Entscheidungen zu Import, Fehlersuche und Testen kombinieren10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine Simulation legt einmal einen Startwert fest und ruft dann 50-mal random.randint(2, 5) auf. Ein neuer Test legt bei derselben Python-Version denselben Startwert fest und wiederholt dieselben Aufrufe. Was sollten seine Prüfungen erwarten?
  1. Die Folge wiederholt sich und jedes Ergebnis liegt von 2 bis einschließlich 5.
  2. Die Folge wiederholt sich und jedes Ergebnis liegt von 2 bis einschließlich 4.
  3. Jedes Ergebnis tritt gleich oft auf und alle vier Werte müssen erscheinen.
  4. Jeder Aufruf ergibt wieder das erste Ergebnis, weil der Startwert gesetzt bleibt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Die Dokumentation nennt beautifulsoup4 als Distribution und bs4 als deren Modul. Ein Skript importiert bs4 erfolgreich. Ein Kollege möchte python -m pip install beautifulsoup4 ändern und bs4 installieren, damit die Namen übereinstimmen. Ist die Übereinstimmung der Namen ein guter Grund für diese Änderung?
  1. Ja; jeder erfolgreiche Import muss den Installationsnamen der Distribution verwenden.
  2. Ja; der Import von bs4 beweist, dass pip eine Distribution unter diesem Namen installiert hat.
  3. Nein; die Installation folgt dem dokumentierten Distributionsnamen, der abweichen kann.
  4. Nein; das Modul muss zuerst passend zur aktuellen Distribution umbenannt werden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein neuer Lauf von display.py meldet von oben nach unten diese Aufrufe: start(" "), read_count(text) und dann int(text); er endet mit ValueError. Welche Folge von Schritten prüft vor einer Korrektur die wahrscheinliche Ursache am besten?
  1. Prüfe nur type(text); eine Zeichenkette genügt, um einen Typfehler festzustellen.
  2. Prüfe repr(text), bestätige die leere Eingabe und lege dann das Eingabeverhalten fest.
  3. Verschiebe dieselbe Umwandlung nach start, damit sie vor den anderen Funktionsaufrufen läuft.
  4. Ersetze jede fehlgeschlagene Umwandlung durch null, ohne das geforderte Eingabeverhalten zu prüfen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Eine Summenfunktion überspringt das erste Element. Eine Behelfslösung addiert 6 zu jeder zurückgegebenen Summe und besteht nun für [6, 3, 2]. Welche erwarteten und tatsächlichen Ergebnisse für zwei neue Eingaben decken das verbleibende Problem auf?
  1. [9]: erwartet 9, tatsächlich 15; []: erwartet 0, tatsächlich 6.
  2. [9]: erwartet 9, tatsächlich 6; []: erwartet 0, tatsächlich 0.
  3. [9]: erwartet 6, tatsächlich 6; []: erwartet 6, tatsächlich 6.
  4. [9]: erwartet 9, tatsächlich 6; []: erwartet 0, tatsächlich 6.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Diese Funktion gibt ein korrektes Produkt aus, aber der aufrufende Code erhält bei area(4, 5) + 1 einen TypeError. Wo solltest du untersuchen und welches Ergebnis erklärt den Fehler?

def area(w, h):
    product = w * h
    print(product)
  1. Führe den Aufruf als Prozedurschritt aus; er gibt die ganze Zahl 20 zurück.
  2. Führe den Aufruf als Prozedurschritt aus; er gibt die Zeichenkette "20" zurück.
  3. Führe den Aufruf als Prozedurschritt aus; er gibt None zurück.
  4. Steige in den Aufruf ein; sein ausgegebenes Ergebnis wird zum Rückgabewert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Was geschieht bei einer gewöhnlichen, nicht optimierten Ausführung?

import math
assert math.isclose(0.1 + 0.2, 0.3)
assert 0.1 + 0.2 == 0.3
  1. Die erste Zusicherung besteht; die zweite löst AssertionError aus.
  2. Beide Zusicherungen bestehen, weil Dezimalsummen exakt gespeichert werden.
  3. Die erste Zusicherung schlägt fehl; die zweite wird nie ausgeführt.
  4. Beide Zusicherungen schlagen fehl, aber das Programm läuft bis zum Ende weiter.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

pick() gibt eine zufällige ganze Zahl von 3 bis einschließlich 7 zurück. pair_total() addiert die Ergebnisse zweier Aufrufe von pick(). Ein Test, der für jede Summe ohne festgelegten Startwert den Wert 10 verlangt, schlägt manchmal fehl, obwohl beide Funktionen richtig arbeiten. Welche Prüfung jedes Ergebnisses entspricht dem geforderten Summenbereich?
  1. Prüfe 3 <= value <= 7 für jede Summe.
  2. Prüfe 6 <= value < 14 für jede Summe.
  3. Prüfe value == 10 für jede Summe.
  4. Prüfe 6 <= value <= 14 für jede Summe.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

reserve(n) muss ganzzahlige Anzahlen von 0 bis einschließlich 8 akzeptieren und außerhalb dieses Bereichs ValueError auslösen. Tests mit assertRaises(ValueError) melden für -1 ein F, weil keine Ausnahme auftritt, und für 9 ein E, weil ein TypeError auftritt. Ein Test mit 2 besteht. Welches Verhalten sollte die Korrektur herstellen?
  1. -1 normal akzeptieren; bei 9 ValueError auslösen; 2 gültig lassen.
  2. Bei -1 und 9 ValueError auslösen; 2 gültig lassen.
  3. Bei -1 ValueError auslösen; bei 9 TypeError beibehalten; 2 gültig lassen.
  4. -1 und 9 normal akzeptieren; bei 2 ValueError auslösen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein Skript heißt random.py und importiert random. Danach schlägt es fehl, weil random.randint fehlt. Welche erste Änderung behebt den Namenskonflikt?
  1. Das Modul random erneut mit pip installieren.
  2. import random unter den Aufruf von randint verschieben.
  3. random.py beibehalten und from random import randint verwenden.
  4. Das Skript in draw_numbers.py umbenennen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Ein Programm enthält assert total == 10 für eine interne Berechnung und assert age >= 0 für eine Benutzereingabe. Es läuft mit -O, wobei total gleich 9 und age gleich -1 ist. Was geschieht mit diesen Prüfungen und welche Änderung erhält die erforderliche Eingabevalidierung?
  1. Nur die Summenprüfung entfällt; gib der Alterszusicherung eine längere Meldung.
  2. Beide Prüfungen entfallen; setze Altersbedingung und Meldung in ein Tupel.
  3. Beide Prüfungen entfallen; verwende if age < 0 und eine Fehlerreaktion für die Eingabe.
  4. Nur die Altersprüfung entfällt; verschiebe sie in eine Funktion namens test_age.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

60 Schlüsselbegriffe, jeweils mit Definition

A

Ablauftabelle
Eine Ablauftabelle hält Variablenwerte bei aufeinanderfolgenden Ausführungsschritten fest, sodass du ein Programm von Hand verfolgen und seine Änderungen untersuchen kannst.
Eine Ablauftabelle für eine aufsummierende Schleife zeigt die Summe vor und nach der Addition jedes Elements.
Abrundungsfunktion
Die Abrundungsfunktion liefert zu einer Zahl die größte ganze Zahl, die nicht größer als diese Zahl ist; math.floor rundet bei Bedarf in Richtung minus unendlich.
Der abgerundete Wert von -3,2 ist -4, sodass sich math.floor(-3.2) von der Umwandlung mit int(-3.2) unterscheidet.
Alias
Ein Alias ist der mit as gewählte Name für ein importiertes Modul oder Objekt; der Import bindet diesen Namen im importierenden Programm.
Der Alias stats in import statistics as stats ermöglicht dem Skript den Aufruf stats.mean([1, 3, 8]).
AssertionError
Ein AssertionError signalisiert eine fehlgeschlagene Zusicherung und kann eine angegebene Meldung enthalten, die erklärt, welche Erwartung die Prüfung nicht erfüllt hat.
Ein AssertionError mit "wrong total" lenkt die Aufmerksamkeit auf den Test, der die berechnete Summe verglichen hat.
Aufrufkette
Eine Aufrufkette ist die Folge aktiver Funktionsaufrufe, die zur aktuellen Operation geführt haben, vom äußeren Aufruf bis zum neuesten Aufruf.
Eine Aufrufkette von einer Funktion report zu einer Funktion average zeigt, wie eine Liste die Funktion erreichte, die durch ihre Länge dividierte.
Aufrufrahmen
Ein Aufrufrahmen in einem Traceback bezeichnet eine aktive Aufrufstelle durch Datei, Zeilennummer und Funktion und zeigt die relevante Quellcodezeile.
Der unterste Aufrufrahmen kann eine Division durch die Länge einer leeren Liste zeigen, während frühere Aufrufrahmen erkennen lassen, welcher Aufruf diese Liste geliefert hat.
Aufrundungsfunktion
Die Aufrundungsfunktion liefert zu einer Zahl die kleinste ganze Zahl, die nicht kleiner als diese Zahl ist; math.ceil führt diese Rundung zur größeren ganzen Zahl aus.
Eine Aufrundung macht aus 3,4 benötigten Farbdosen vier ganze Dosen, die für die angegebene Fläche ausreichen.
Ausnahme
Eine Ausnahme signalisiert ein während der Ausführung erkanntes Problem; eine unbehandelte Ausnahme stoppt das Programm und erzeugt normalerweise einen Traceback.
Eine Ausnahme durch Division durch null kann average stoppen, bevor der aufrufende Code das berechnete arithmetische Mittel ausgibt.
automatische Testerkennung
Die automatische Testerkennung findet ausführbare Tests anhand von Regeln für Datei- und Methodennamen, etwa anhand des unittest-Standardmusters test*.py für Dateien.
Die automatische Testerkennung mit python -m unittest kann passende Dateien ausführen, ohne jede einzeln im Befehl aufzuführen.

C

Code auf Modulebene
Code auf Modulebene besteht aus Anweisungen auf Modulebene außerhalb von Funktionskörpern, die beim ersten Laden eines Moduls der Reihe nach ausgeführt werden.
Code auf Modulebene, der print aufruft, kann beim Import eine Ausgabe erzeugen, selbst wenn der importierende Code keine Funktion aufruft.

D

Debugger
Ein Debugger hält die Programmausführung an und stellt Bedienelemente bereit, um aktuelle Werte zu untersuchen und Code Schritt für Schritt auszuführen.
Ein Debugger ermöglicht dir, in calculate einzusteigen und dessen Argumente zu untersuchen, wenn der aufrufende Code eine falsche Antwort erhält.
direkte Veränderung eines Objekts
Eine direkte Veränderung eines Objekts ändert ein vorhandenes Objekt, etwa eine Liste, ohne für den veränderten Inhalt ein neues Objekt zu benötigen.
Die direkte Veränderung eines Objekts durch random.shuffle(cards) ändert cards und gibt None zurück, sodass keine Zuweisung nötig ist.
Distribution
Eine Distribution ist ein installierbares Python-Projekt mit einem Namen für die Paketverwaltung, der sich vom Namen bei Importen unterscheiden kann.
Die Distribution beautifulsoup4 wird unter diesem Namen installiert, aber ihre Dokumentation weist Python-Nutzer an, bs4 zu importieren.
Docstring
Ein Docstring ist eine Zeichenkette am Anfang eines Moduls oder einer Funktion, die dessen oder deren Zweck dokumentiert und über help() angezeigt werden kann.
Ein Docstring für circle_area kann das Radiusargument und den an den aufrufenden Code zurückgegebenen Flächeninhalt erklären.

E

Eingabevalidierung
Die Eingabevalidierung prüft, ob externe Daten die Anforderungen eines Programms erfüllen, und reagiert auf ungeeignete Eingaben, bevor sie verwendet werden.
Eine Eingabevalidierung mit if score < 0 bleibt aktiv, wenn Python ohne Zusicherungen ausgeführt wird.
Einzelschritt
Ein Einzelschritt ist eine Debugger-Aktion, die in eine in der aktuellen Zeile aufgerufene Funktion einsteigt, sodass du die Schritte innerhalb dieser Funktion untersuchen kannst.
Verwende bei result = convert(text) einen Einzelschritt, wenn der Rückgabewert falsch ist und der Eingabetext korrekt aussieht.

F

Fehlersuche mit Ausgaben
Bei der Fehlersuche mit Ausgaben werden an ausgewählten Codestellen vorübergehende Ausgaben ergänzt, um Werte, Ausführungsreihenfolge und die Übereinstimmung einer Hypothese mit dem Verhalten sichtbar zu machen.
Bei der Fehlersuche mit Ausgaben beschriftet print(f"{i=} {total=}") den Schleifenindex und die Summe zum untersuchten Zeitpunkt.
Fehlersuche und Fehlerbehebung
Fehlersuche und Fehlerbehebung umfasst, unerwartetes Verhalten zu reproduzieren, seine Ursache zu finden und zu beheben sowie das betroffene Verhalten erneut zu prüfen.
Zur Fehlersuche bei einer Schleife, die Preise summiert, gehört es, die besuchten Indizes zu beobachten, bevor der Startwert der Schleife geändert wird.
fehlgeschlagener Test
Ein fehlgeschlagener Test ist ein Testergebnis, das durch eine falsche Zusicherung entsteht, etwa wenn ein tatsächlicher Rückgabewert vom spezifizierten erwarteten Wert abweicht.
Ein mit F markierter fehlgeschlagener Test kann zeigen, dass die Funktion "B" zurückgegeben hat, wo die geprüfte Regel "A" verlangte.

G

Grenzfall
Ein Grenzfall ist eine Testeingabe an einer Grenze, an der eine Regel wechselt. Damit lassen sich Fehler bei ein- und ausschließenden Vergleichen leichter erkennen.
Ein Grenzfall bei der Punktzahl 90 prüft, ob die Regel für die Note A den erforderlichen einschließenden Vergleich verwendet.

H

Haltepunkt
Ein Haltepunkt markiert eine Stelle, an der ein Debugger die Ausführung anhält, sodass du den Zustand untersuchen kannst, bevor der folgende Code ausgeführt wird.
Ein Haltepunkt vor einer Schleifenaktualisierung lässt dich die aktuelle Summe mit dem Element vergleichen, das gleich addiert wird.
Hauptprogrammschutz
Ein Hauptprogrammschutz ist ein if __name__ == "__main__":-Block, der seinen Körper bei direkter Ausführung ausführt und bei einem gewöhnlichen Import überspringt.
Ein Hauptprogrammschutz um main() ermöglicht Tests, die Funktionen des Moduls zu importieren, ohne dessen Anwendung zu starten.
Hypothese
Eine Hypothese ist eine konkrete vorgeschlagene Erklärung für einen Programmfehler, die eine Beobachtung vorhersagt, die du im laufenden Programm prüfen kannst.
Die Hypothese, dass eine Schleife ihr erstes Element überspringt, sagt voraus, dass eine Ausgabe ihrer Indizes nie 0 zeigt.

I

ImportError
Ein ImportError kann auftreten, wenn from einen Namen anfordert, der in einem Modul nicht verfügbar ist, obwohl Python das Modul selbst gefunden hat.
Ein ImportError bei from math import square_root weist auf den angeforderten Namen hin, nicht auf eine fehlende Installation.
IndexError
Ein IndexError tritt auf, wenn ein Zugriff auf eine Sequenz eine nicht vorhandene Position anfordert, etwa Index 3 in einer Liste mit drei Elementen.
Ein IndexError bei names[4] legt nahe, die Länge der Liste und die Schleifenschranken zu prüfen, die 4 erzeugt haben.
Interpreter
Ein Interpreter ist das Programm, das Python-Code ausführt; verschiedenen installierten Interpretern können unterschiedliche Pakete von Drittanbietern zur Verfügung stehen.
Die Wahl des Interpreters im Editor erklärt, warum ein für ein anderes Python installiertes Paket dennoch fehlen kann.

K

KeyError
Ein KeyError tritt auf, wenn ein Wörterbuchzugriff einen fehlenden Schlüssel anfordert, sodass Python über den Indexzugriff keinen Wert für diesen Schlüssel zurückgeben kann.
Ein KeyError für "price" kann zeigen, dass das aktuelle Wörterbuch den erwarteten Preiseintrag nie erhalten hat.

L

Laufzeitfehler
Ein Laufzeitfehler ist ein Problem, das während der Codeausführung erkannt wird, etwa eine ungültige Operation, die in diesem Moment eine Ausnahme auslöst.
Ein Laufzeitfehler tritt auf, wenn ein gültiger Divisionsausdruck mit einem Divisor erreicht wird, dessen Wert null ist.
Logikfehler
Ein Logikfehler bewirkt, dass sich ein Programm falsch verhält, obwohl seine Anweisungen ausgeführt werden, ohne einen Ausnahmebericht zu erzeugen.
Ein Logikfehler in einer Schleife, die bei Index 1 beginnt, überspringt den ersten Preis und ergibt eine zu kleine Summe.

M

minimales reproduzierbares Beispiel
Ein minimales reproduzierbares Beispiel besteht aus dem kürzesten Code und der kleinsten Eingabe, bei denen ein Fehlerfall erhalten bleibt, sodass die relevanten Schritte direkt untersucht werden können.
Ein minimales reproduzierbares Beispiel kann Hunderte von Datensätzen auf die zwei reduzieren, die noch denselben Fehler auslösen.
Modul
Ein Modul ist eine Einheit von Python-Code, meist eine .py-Datei, deren Funktionen und Variablen zur Verwendung in einem anderen Programm importiert werden können.
Das Modul math stellt sqrt bereit, sodass ein Programm Quadratwurzeln berechnen kann, ohne diese Funktion zu definieren.
Modulsuchpfad
Der Modulsuchpfad ist die geordnete Liste der Ordner in sys.path, die Python bei der Suche nach Importen nach seinen eingebauten Modulen prüft.
Eine Hilfsdatei außerhalb des Modulsuchpfads kann ModuleNotFoundError verursachen, wenn das Skript sie importiert.
Modulverdeckung
Modulverdeckung liegt vor, wenn ein früher gefundenes Modul denselben Namen wie das beabsichtigte Modul hat und dieses bei der Importsuche verdeckt.
Eine Modulverdeckung durch eine lokale Datei random.py kann dazu führen, dass einem Skript die Bibliotheksfunktion randint fehlt.

N

NameError
Ein NameError tritt auf, wenn Python keine Bindung für einen in einem Ausdruck verwendeten Namen finden kann, häufig wegen eines Tippfehlers oder fehlenden Imports.
Ein NameError für sqrt nach alleinigem import math bedeutet, dass die Funktion dort das Präfix math. benötigt.

O

Optimierungsoption
Die Optimierungsoption -O verändert die Python-Ausführung, indem sie assert-Anweisungen entfernt. Erforderliche Validierungen können sich daher nicht auf diese Anweisungen verlassen.
Wird ein Skript mit der Optimierungsoption gestartet, entfällt eine Prüfung auf ein negatives Alter, die nur aus einer Zusicherung besteht.

P

Paket
Ein Paket bündelt zusammengehörige Python-Module, üblicherweise in einem Ordner, sodass Programme eine größere Sammlung von Code organisieren und wiederverwenden können.
Ein Paket eines Drittanbieters kann mehrere zusammengehörige Module bereitstellen, die ein Programm für unterschiedliche Aufgaben importiert.
pip
pip ist ein Installationswerkzeug, das Python-Distributionen von Drittanbietern für den Interpreter herunterlädt und verwaltet, der es ausführt.
Der Aufruf python3 -m pip show cowsay weist das zu python3 gehörende pip an, die Installationsdetails dieses Pakets anzuzeigen.
Programmfehler
Ein Programmfehler ist ein Fehler, durch den das Verhalten eines Programms von seinem beabsichtigten Verhalten abweicht. Dazu gehören falsche Antworten und unerwartete Fehlschläge.
Ein Programmfehler, der den ersten Preis überspringt, lässt sich mit einer Liste mit einem Element reproduzieren, deren erwartete Summe leicht zu prüfen ist.
Prozedurschritt
Ein Prozedurschritt ist eine Debugger-Aktion, die die aktuelle Zeile einschließlich aufgerufener Funktionen ausführt, ohne deren interne Zeilen zu verfolgen.
Verwende bei einem Berechnungsaufruf einen Prozedurschritt, wenn du dessen Rückgabewert im aufrufenden Code untersuchen möchtest.
Pseudozufallszahl
Eine Pseudozufallszahl wird von einem deterministischen Algorithmus erzeugt, dessen Folge für Anwendungen wie Simulationen zufällig aussehen soll.
Eine Pseudozufallszahl aus random.randint(1, 6) kann in einer Brettspielsimulation ein Würfelergebnis darstellen.
Punktnotation
Mit Punktnotation wird auf ein benanntes Attribut innerhalb eines Objekts oder Moduls zugegriffen, indem zwischen Objektname und Attributname ein Punkt steht.
Die Punktnotation in math.sqrt(25) findet die Funktion sqrt innerhalb des bereits importierten Moduls math.
PyPI
PyPI ist der Python Package Index, ein öffentliches Verzeichnis, in dem Herausgeber Distributionen von Drittanbietern zur Installation bereitstellen.
Die PyPI-Seite eines Pakets bietet Projektinformationen und Dokumentation, die du vor der Installation prüfen kannst.

R

Randfall
Ein Randfall ist eine ungewöhnliche Eingabe an einer extremen oder besonderen Grenze, etwa eine leere Liste. Sie kann Verhalten aufdecken, das gewöhnliche Eingaben übersehen lassen.
Ein Randfall mit einer Liste mit einem Element kann eine Summenfunktion aufdecken, die ihre Schleife beim zweiten Element beginnt.
Regression
Eine Regression ist ein neu eingeführter Fehler in zuvor funktionierendem Verhalten, oft nachdem eine Änderung Code verändert hat, von dem andere Funktionen oder Tests abhängen.
Eine Regression kann dazu führen, dass eine zuvor bestandene Summenprüfung mit einem Element nach einer Änderung zur Korrektur leerer Eingaben fehlschlägt.

S

Spezifikation
Eine Spezifikation beschreibt das Verhalten, das eine Funktion bieten muss. Sie bildet eine unabhängige Grundlage für Eingaben, erwartete Ergebnisse und geeignete Testprüfungen.
Die Spezifikation, dass Punktzahlen ab 90 ein A erhalten, legt die erwartete Antwort für einen Test mit genau 90 fest.
Standardbibliothek
Die Standardbibliothek ist die Sammlung der mit Python gelieferten Module. Sie stellt fertige Werkzeuge ohne separate Paketinstallation bereit.
Die Standardbibliothek enthält math für Berechnungen und random für Simulationen wie Würfelwürfe.
Startwert des Zufallszahlengenerators
Ein Startwert des Zufallszahlengenerators initialisiert einen Pseudozufallszahlengenerator, sodass dieselbe Aufruffolge bei derselben Python-Version wiederholt werden kann.
Wird der Startwert vor einer Simulation gesetzt, kann eine programmierende Person bei der Fehlersuche dieselbe Folge erneut untersuchen.
Syntaxfehler
Ein Syntaxfehler bedeutet, dass Code Pythons Grammatik verletzt, etwa durch einen fehlenden Doppelpunkt, und verhindert den normalen Start des betroffenen Skripts.
Ein Syntaxfehler nach if ready lässt sich beheben, indem du den vor dem eingerückten Block erforderlichen Doppelpunkt ergänzt.

T

Teile und herrsche
Teile und herrsche grenzt die Fehlersuche ein, indem benötigte Zwischenwerte geprüft werden und der Abschnitt verfolgt wird, in dem sie zuerst falsch werden.
Teile und herrsche lenkt die Aufmerksamkeit auf die Umwandlung, wenn Rohdaten korrekt, umgewandelte Werte aber bereits falsch sind.
TestCase
Ein TestCase ist die Basisklasse von unittest für Testklassen. Sie stellt Zusicherungsmethoden und Unterstützung für die Ausführung jedes erkannten Tests bereit.
Eine Klasse, die von unittest.TestCase erbt, kann innerhalb ihrer benannten Testmethoden self.assertEqual aufrufen.
Testfehler
Ein Testfehler ist ein Testergebnis, das durch eine unerwartete Ausnahme außer einer fehlgeschlagenen Zusicherung im Test oder im aufgerufenen Code entsteht.
Ein mit E markierter Testfehler kann entstehen, wenn eine Funktion TypeError auslöst, bevor die Gleichheitsprüfung einen Wert erhält.
Testmethode
Eine Testmethode ist eine Funktion innerhalb einer Testklasse, deren Name mit test beginnt, sodass unittest ihre Prüfungen finden und ausführen kann.
Eine Testmethode namens test_limit kann einen Grenzfall getrennt vom Test einer gewöhnlichen Eingabe prüfen.
Traceback
Ein Traceback berichtet über die bei einer unbehandelten Ausnahme aktive Aufrufkette und endet mit dem Ausnahmetyp und seiner Meldung.
Lies zuerst die letzte Zeile des Tracebacks und verfolge dann den fehlerauslösenden Aufrufrahmen nach oben bis zum ursprünglichen Aufruf.
TypeError
Ein TypeError signalisiert einen für eine Operation ungeeigneten Datentyp oder eine falsche Anzahl von Argumenten bei einem Funktionsaufruf, etwa ein fehlendes erforderliches Argument.
Ein TypeError bei "Score: " + 8 weist auf eine Zeichenkette und eine ganze Zahl hin, die mit diesem Ausdruck nicht verknüpft werden können.
Typosquatting
Typosquatting bezeichnet das Veröffentlichen unter einem ähnlich aussehenden Namen, um Personen abzufangen, die bei der Softwareinstallation den Namen eines vertrauenswürdigen Projekts falsch eingeben.
Die genaue Schreibweise eines Projekts auf PyPI zu prüfen, hilft beim Kopieren eines Installationsbefehls, Typosquatting zu vermeiden.

U

Unit-Test
Ein Unit-Test ist eine kleine automatisierte Prüfung einer Einheit wie einer Funktion. Er vergleicht ihr Verhalten bei einer gewählten Eingabe mit einem erwarteten Ergebnis.
Ein Unit-Test prüft, ob eine Preisfunktion für eine leere Liste 0 zurückgibt, wenn ihre Spezifikation dieses Ergebnis verlangt.

V

ValueError
Ein ValueError signalisiert, dass eine Operation den Datentyp einer Eingabe akzeptiert, aber deren konkreten Wert nicht verwenden kann, etwa ungültigen Zahlentext.
Ein ValueError bei int("6.2") bedeutet, dass die Zeichenkette keine ganze Zahl in der geforderten Form beschreibt.

W

Wildcard-Import
Ein Wildcard-Import verwendet *, um die öffentlichen Namen eines Moduls in das aktuelle Programm zu übernehmen. Das kann ihre Herkunft verschleiern und vorhandene Bindungen ersetzen.
Der Wildcard-Import from math import * kann eine Variable namens e durch die mathematische Konstante ersetzen.

Z

Ziehen ohne Zurücklegen
Ziehen ohne Zurücklegen wählt unterschiedliche Eingabepositionen aus, sodass jede Position höchstens einmal gewählt wird, selbst wenn Werte mehrfach vorkommen.
Beim Ziehen ohne Zurücklegen aus ["A", "A", "B"] können beide Positionen gewählt werden, die "A" enthalten.
Zusicherung
Eine Zusicherung prüft eine Bedingung, die bei korrektem Code gelten soll. Ist sie wahr, läuft die Ausführung weiter; ist sie falsch, wird AssertionError ausgelöst.
Eine Zusicherung wie assert count == 3 prüft ein internes Ergebnis gegen die unabhängig erwartete Anzahl.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten