Python-Kurs / Ausnahmen mit try, except, else, finally und raise behandeln
Eine Ausnahmebehandlung unterscheidet erwartete Fehler, auf die das Programm sinnvoll reagieren kann, von Fehlern, die an den Aufrufer weitergegeben werden müssen. Halten Sie den try-Block klein und fangen Sie nur passende Fehlerarten ab, damit andere Defekte sichtbar bleiben.
try, except, else und finally im Ablauf unterscheiden
Im try-Block steht die Operation, deren erwartete Fehler behandelt werden sollen. Löst sie eine Ausnahme aus, werden die restlichen Anweisungen dieses Blocks übersprungen und ein passender except-Zweig wird gesucht. Ein else-Zweig wird ausgeführt, wenn der try-Block ohne Ausnahme normal abgeschlossen wurde. Das macht die erfolgreiche Weiterverarbeitung sichtbar, ohne unnötig viel Code in den geschützten Bereich zu ziehen.
finally führt beim Verlassen dieses Bereichs die dort angegebene Bereinigung aus, sowohl auf einem normalen als auch auf einem Ausnahmeweg. Es bedeutet nicht „alle Fehler wurden behoben“. Eine nicht behandelte Ausnahme wird nach der Bereinigung weitergegeben. Diese Garantie bezieht sich auf den gewöhnlichen Python-Kontrollfluss, nicht auf ein hartes Beenden des Prozesses oder einen Systemausfall.
Mit raise können Sie eine verletzte Eingaberegel ausdrücklich melden. Entscheiden Sie dabei, an welcher Grenze eine Wiederholung oder eine verständliche Meldung möglich ist. Eine fehlerhafte Eingabe ist anders zu behandeln als ein Speicherfehler, für den die aktuelle Funktion keine verlässliche Wiederherstellung kennt. Die Einführung zu Fehlern und Ausnahmen beschreibt diese Abläufe.
Gültige und ungültige Beträge vollständig testen
Speichern Sie den folgenden vollständigen Code als exceptions_demo.py in UTF-8 im Übungsordner. Führen Sie python exceptions_demo.py mit dem Projektinterpreter aus. Außerhalb einer aktivierten Umgebung kann unter macOS oder Ubuntu python3 der passende Name sein. Zusatzpakete und externe Dateien sind nicht erforderlich.
def parse_amount(text):
amount = int(text)
if amount < 0:
raise ValueError("amount must be nonnegative")
return amount
for text in ["8000", "abc", "-1"]:
try:
amount = parse_amount(text)
except ValueError as error:
print("invalid:", text)
else:
print("accepted:", amount)
finally:
print("checked")
Erwartete Ausgabe:
accepted: 8000
checked
invalid: abc
checked
invalid: -1
checked
Für "8000" konvertiert int den Text erfolgreich und die Funktion gibt die Zahl zurück. Deshalb läuft else und zeigt accepted: 8000. Bei "abc" scheitert bereits die Konvertierung. Bei "-1" gelingt die Konvertierung, aber die eigene Negativprüfung löst einen weiteren ValueError aus. Beide erwarteten Fehlerarten führen hier zu einer einheitlichen Ablehnung.
Nach jedem dieser drei Fälle wird checked ausgegeben. Dies macht den abschließenden Schritt sichtbar; es bestätigt nicht, dass der Betrag gültig war. Die Schleife geht nach einem behandelten Fehler mit dem nächsten Text weiter. Die Übung zu Funktionen und Rückgabewerten hilft, die erfolgreiche Rückgabe von der Behandlung des fehlgeschlagenen Aufrufs zu unterscheiden.
Behandeln, erneut auslösen und Ursachen erhalten
except ValueError passt zur hier erwarteten Zahlenkonvertierung und zur eigenen Betragsregel. Wird dagegen ein unerwartetes Objekt wie None an int übergeben, entsteht ein TypeError. Der vorhandene Handler fängt ihn nicht ab. finally läuft noch, anschließend bleibt der Fehler sichtbar und die unbehandelte Ausführung endet.
Ein pauschales except Exception: pass kann solche Probleme verdecken und das Programm mit unvollständigem Zustand weiterarbeiten lassen. Nach einem abgefangenen Fehler besitzt eine Zuweisung außerdem nicht automatisch einen neuen gültigen Wert: Wenn der Aufruf rechts von amount = parse_amount(text) scheitert, wird dieser Zuweisungsschritt nicht abgeschlossen. Verwenden Sie das Ergebnis daher wie im Beispiel nur im erfolgreichen else-Zweig und verlassen Sie sich nicht auf einen möglicherweise früher gespeicherten Wert.
Ein alleinstehendes raise innerhalb eines Handlers gibt die aktuell behandelte Ausnahme weiter. Das unterscheidet sich vom Zurückgeben eines Ersatzwerts, mit dem der Aufrufer normal weiterläuft. Soll eine Schnittstelle einen fachlich passenderen Fehler melden, kann sie beispielsweise raise RuntimeError("amount import failed") from error verwenden. Diese Form erhält die ursprüngliche Ausnahme als ausdrückliche Ursache. Sie ist ein Muster für eine passende Grenze, keine Aufforderung, jede Ausnahme in RuntimeError umzubenennen.
Ressourcen lassen sich häufig mit with verwalten, wie in der Textdatei-Übung. Bei manueller Bereinigung müssen Sie berücksichtigen, dass die Ressource schon beim Öffnen fehlschlagen kann und dann nicht existiert. Ein return im finally-Block kann einen ausstehenden Fehler unterdrücken oder einen zuvor festgelegten Rückgabewert ersetzen. Lassen Sie diesen Block deshalb bereinigen, statt dort ein scheinbar erfolgreiches Ergebnis zu erzwingen.
Erfolgs-, Fehler- und Bereinigungswege vergleichen
- Ergänzen Sie
"0"in der Testliste. Es mussaccepted: 0und danachcheckederscheinen, weil null hier erlaubt ist. - Testen Sie eine leere Zeichenkette. Die Umwandlung scheitert; die Ausgabe enthält
invalid:für diesen leeren Wert und anschließendchecked. - Geben Sie für diese lokalen Beispieldaten vorübergehend im Handler zusätzlich
type(error).__name__undstr(error)aus. Vergleichen Sie die Ursache bei"abc"mit der selbst formulierten Negativmeldung. Beide sindValueError, stammen aber aus unterschiedlichen Prüfungen. - Ersetzen Sie den Handlerinhalt testweise durch ein alleinstehendes
raise. Die erste ungültige Eingabe beendet nachcheckeddie weitere unbehandelte Verarbeitung. Stellen Sie anschließend die ursprüngliche Ausgabe im Handler wieder her. - Stellen Sie die ursprüngliche Liste und sämtliche Ausgaben wieder her und vergleichen Sie alle sechs Zeilen mit dem Beispiel.
Verwenden Sie Diagnoseausgaben aus diesem Experiment nicht ungeprüft für echte Benutzerdaten. Ausnahmeinformationen können Eingaben, Dateipfade oder vertrauliche Werte enthalten. Geben Sie dem Nutzer eine korrigierbare Erklärung und halten Sie interne Diagnosen auf den notwendigen Umfang beschränkt. Erfolgreiche Wiederherstellung, bewusst verworfene Eingaben und ein weitergegebener Systemfehler sollten im Ergebnis erkennbar verschieden bleiben.




