Exceptions
Kurz gesagt: Eine Exception ist ein Objekt, das einen Fehler beschreibt, der während des Programmlaufs passiert ist: Der Traceback zeigt, wo, und try und except fangen ihn, damit das Programm weiterlaufen kann.
Problem
12a statt 12
Die Konzertkasse fragt, wie viele Tickets du willst. Ein Ticket kostet 15 €.
tickets = int(input("Wie viele Tickets? "))print(f"Gesamt: {tickets * 15} €")Mit der Eingabe 12 sagt das Programm „Gesamt: 180 €“. Aber der Kunde hat es eilig und tippt einen Buchstaben zu viel:
Wie viele Tickets? 12aTraceback (most recent call last): File "/projects/tickets/tickets.py", line 1, in <module> tickets = int(input("Wie viele Tickets? ")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ValueError: invalid literal for int() with base 10: '12a'Das Programm hält an. Statt der Summe kommt ein langer Text, und die Zeile „Gesamt“ wird nie erreicht. Was bedeutet dieser Text, und wie verhinderst du, dass das Programm wegen eines Buchstabens anhält?
Die Idee
Exception
int() muss eine Zahl zurückgeben. Aus „12a“ kann es keine Zahl machen, und irgendeine Zahl zurückzugeben wäre gelogen. Deshalb erzeugt die Funktion ein Objekt, das das Problem beschreibt, und wirft es. Dieses Objekt heißt Exception (Ausnahme).
In Python heißt das Wort raise („erheben“), aber die Bedeutung ist dieselbe. Wenn niemand sie fängt, hält das Programm an und zeigt, was passiert ist. Dieser Text heißt Traceback, und du liest ihn von unten nach oben, weil das Neueste ganz unten steht (most recent call last):
- Die letzte Zeile: die Art der Exception und die Meldung.
ValueError: invalid literal for int() with base 10: '12a': ein falscher Wert, und hier ist der Text. - Die „File“-Zeilen darüber: wo es passiert ist. Das ist der Aufrufstapel aus der Lektion über Rekursion, aber von außen nach innen: Ganz oben ist die äußerste Stelle, und ganz unten ist die Funktion, die geworfen hat.
<module>bedeutet den Code auf oberster Ebene der Datei. - Deine Zeile: die letzte „File“-Zeile, die auf deine Datei zeigt. Hier:
tickets.py,line 1. Darunter steht die Zeile selbst, und die Zeichen^^^markieren den Teil, der geworfen hat.
Die Meldungen sind auf Englisch, weil die Sprache sie schreibt, nicht du.
Probier es aus
Finde den Fehler
Das Programm soll das letzte Ergebnis aus der Klassenarbeit ausgeben. Es hält damit an:
Traceback (most recent call last): File "/projects/tickets/scores.py", line 6, in <module> print(last_score(scores)) ^^^^^^^^^^^^^^^^^^ File "/projects/tickets/scores.py", line 2, in last_score return scores[len(scores)] ~~~~~~^^^^^^^^^^^^^IndexError: list index out of rangeLies den Traceback. In welcher Zeile des Programms steckt der Fehler?
Wähle die Zeile mit dem Fehler.
last_score, Zeile 2. Die Zeile darüber ist Zeile 6: Von dort wurde die Funktion aufgerufen, aber der Fehler ist nicht dort. Die letzte Zeile sagt auch, was es ist: ein Index außerhalb der Liste. Bei 5 Elementen ist der letzte Index len(scores) - 1. In Python geht es auch kürzer: scores[-1] ist das letzte Element.Die Idee
try und except
Eine Exception kann man fangen. Der Code, der werfen könnte, kommt in try („versuche“). Was bei einem Fehler passieren soll, schreibst du in except („außer“, also „außer wenn das passiert“):
text = input("Wie viele Tickets? ")try: tickets = int(text) print(f"Gesamt: {tickets * 15} €")except ValueError: print("Das ist keine ganze Zahl.")print("Vielen Dank!")12aWie viele Tickets? Das ist keine ganze Zahl.Vielen Dank!- Nach
exceptschreibst du, welche Art von Exception du fängst, hierValueError. - Wenn im
tryalles gut geht, wirdexceptübersprungen. Mit der Eingabe12ist die Ausgabe „Gesamt: 180 €“ und „Vielen Dank!“. - Nach
exceptmacht das Programm weiter. Es hält nicht mehr an.
text = input("Wie viele Tickets? ")try: tickets = int(text) print(f"Gesamt: {tickets * 15} €")except ValueError: print("Das ist keine ganze Zahl.")print("Vielen Dank!")Schritt für Schritt, in Worten
- Das Programm fragt, wie viele Tickets. Du tippst „12a“.
- Im try: int() versucht, aus „12a“ eine Zahl zu machen.
- Das geht nicht. Die Funktion wirft ValueError.
- Die Ausführung springt direkt in except. Die Zeile mit „Gesamt“ wird übersprungen.
- except ist für genau diese Art von Fehler da: Es gibt die Meldung für den Kunden aus.
- Nach except macht das Programm weiter. Es hält nicht an.
Genauer, für Neugierige
- In Python existiert eine Variable, die im
tryentsteht, auch danach: Blöcke haben keinen eigenen Gültigkeitsbereich. Aber wennint()geworfen hat, wirdticketsgar nicht erst erzeugt, undprint(tickets)nach dem Block hält mitNameErroran.
try: tickets = int("12")except ValueError: print("Das ist keine ganze Zahl.")print(tickets)12- Der Name der Exception ist optional:
except ValueError:. Wenn du ihn brauchst, schreibst duexcept ValueError as e:.
Probier es aus
Welche Zeilen laufen?
Was gibt das Programm aus?
print("Start")try: print("Ich lese") seats = int("zehn") print(f"Gelesen: {seats}")except ValueError: print("Falsche Eingabe")print("Ende")„Ich lese“ wird ausgegeben, weil es vor dem Fehler steht. Dann wirft int(), und die Ausführung springt direkt in except. „Gelesen“ wird übersprungen. Nach except macht das Programm mit „Ende“ weiter.
Die Idee
Was in der Exception steht
Die Exception ist ein Objekt, und e in except ValueError as e: ist die Variable, die darauf zeigt. Die Meldung ist der Text des Objekts selbst: str(e), oder einfach {e} in einem f-String.
try: tickets = int(input()) print(f"Gesamt: {tickets * 15} €")except ValueError as e: print(f"Fehler: {e}")12aFehler: invalid literal for int() with base 10: '12a'Die Meldung ist nützlich für dich, wenn du den Fehler suchst. Dem Kunden zeigst du meistens deinen eigenen Text in seiner Sprache, etwa „Das ist keine ganze Zahl.“
Die Idee
Frag, bis es stimmt
Der Kunde hat sich vertippt. Du musst nicht anhalten. Frag noch einmal:
while True: try: tickets = int(input("Wie viele Tickets? ")) break except ValueError: print("Gib eine ganze Zahl ein, zum Beispiel 3.")print(f"Gesamt: {tickets * 15} €")12azwölf12Wie viele Tickets? Gib eine ganze Zahl ein, zum Beispiel 3.Wie viele Tickets? Gib eine ganze Zahl ein, zum Beispiel 3.Wie viele Tickets? Gesamt: 180 €while True läuft immer weiter, bis break die Schleife beendet. Und break wird nur erreicht, wenn int() Erfolg hat. Bei einem Fehler springt die Ausführung in except, danach beginnt die Schleife von vorn und fragt noch einmal.
Genauer, für Neugierige
- Python hat kein
TryParse.ValueErrorzu fangen ist der übliche Weg: „versuch es und fang den Fehler“ ist in Python eine Gewohnheit. Es gibttext.isdigit(), aber das sagt auch für"-3"False, ersetztint()also nicht:
print("12".isdigit())print("12a".isdigit())print("-3".isdigit())TrueFalseFalseProbier es aus
Division durch null
Nicht jede Exception kommt von der Eingabe. Der durchschnittliche Bestellwert ist der Umsatz geteilt durch die Zahl der Bestellungen. Aber am ersten Tag gibt es keine Bestellungen. Mit Ganzzahldivision hält revenue // orders das Programm an:
ZeroDivisionError: integer division or modulo by zeroUnd mit der gewöhnlichen Division /, die eine Kommazahl ergibt?
Was gibt das Programm aus?
revenue = 90orders = 0average = revenue / ordersprint(average)ZeroDivisionError: mit //, mit / und bei Kommazahlen. Das Programm hält an, statt mit einem falschen Wert weiterzulaufen. Wenn es keine Bestellungen geben kann, prüfe den Divisor mit if oder fange ZeroDivisionError.Genauer, für Neugierige
- Die Kommazahlen von Python folgen dem Standard IEEE 754 und kennen unendlich und
nan, aber die Division durch null liefert sie nicht: Python wirft lieber. Unendlich bekommst du nur, wenn du es ausdrücklich verlangst:
print(float("inf"))print(float("inf") - float("inf"))infnanÜbung
Programme, die nicht anhalten
Löse die Aufgaben in deinem Editor. Gib keine Eingabeaufforderungen aus, damit deine Ausgabe mit dem Beispiel übereinstimmt.
1. Text zu Zahl. Schreibe eine Funktion to_number(text), die den Text als float zurückgibt. Lies zwei Zeilen. Gib für jede die Zahl aus oder eine Meldung, dass es keine Zahl ist. Fange die Exception dort, wo du die Funktion aufrufst.
123.45123.abcDie Zahl ist: 123.45Fehler: 123.abc ist keine Zahl.2. Kein solches Produkt. Die Preise stehen in der Liste [120, 75, 300, 45, 89]. Lies eine Produktnummer von 1 bis 5 und gib ihren Preis aus. Wenn die Nummer außerhalb der Liste liegt, fange die Exception und sag es. Mit der Eingabe 2 ist die Ausgabe Preis: 75 €.
7Es gibt kein Produkt mit der Nummer 7.Vorsicht bei der Nummer 0: In Python wirft prices[-1] nicht. Es ist der letzte Preis, 89 €. Ein negativer Index zählt vom Ende. Füge für 0 also auch ein if hinzu.
3. Durchschnittliche Bestellung. Lies den Umsatz und die Zahl der Bestellungen (ganze Zahlen) und gib den Durchschnitt mit Ganzzahldivision aus. Wenn es keine Bestellungen gibt, fange die Exception. Mit der Eingabe 900 und 4 ist die Ausgabe Durchschnitt: 225 €.
900Noch keine Bestellungen.Weitere Aufgaben
- Alter, bis es stimmt. Frage nach dem Alter, bis die Eingabe eine ganze Zahl von 0 bis 120 ist. Bei Text wie „zwanzig“ sag „Das ist keine Zahl.“, und bei 150 sag „Das Alter muss zwischen 0 und 120 liegen.“ Das eine ist eine Exception, das andere ein
if. - Summe der gültigen. Lies 5 Zeilen. Addiere die, die ganze Zahlen sind, und zähle die übersprungenen: Mit der Eingabe
10,abc,5,7.5,3ist die AusgabeSumme: 18, übersprungen: 2. - Division auf Wunsch. Lies zwei ganze Zahlen und gib den Quotienten aus. Bei Text statt einer Zahl und bei Division durch null hält das Programm nicht an. Es fragt noch einmal nach beiden Zahlen.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Parameter und return · Rekursion · Klassen und Objekte · Instanzmethoden
- Geht weiter in: try, except und finally · Werfen und eigene Exceptions · Reguläre Ausdrücke · Dateien
- Aufgaben zum Thema: Fehler und Exceptions