Unterabschnitte


8. Fehler und Ausnahmen

Bisher wurden Fehlermeldungen lediglich erwähnt, aber wenn Sie die Beispiele ausprobiert haben, werden Sie einige gesehen haben. Es gibt (mindestens) zwei unterscheidbare Arten von Fehlern: Syntaxfehler und Ausnahmen.


8.1 Syntaxfehler

Syntaxfehler, auch als Parsing-Fehler bekannt, sind vielleicht die gängigste Art von Beschwerden, die Sie bekommen, während Sie noch Python lernen:


>>> while 1 print 'Hello world'
  File "<stdin>", line 1
    while 1 print 'Hello world'
                ^
SyntaxError: invalid syntax

Der Parser wiederholt die anstößige Zeile und gibt einen kleinen `Pfeil' an der Stelle aus, wo der Fehler erkannt wurde. Der Fehler wurde von dem Zeichen (engl. token) vor dem Pfeil verursacht (oder zumindest dort entdeckt). Im Beispiel wird der Fehler beim Schlüsselwort print erkannt, da ein Doppelpunkt (":") davor fehlt.

Der Dateiname und die Zeilennummer werden mit ausgegeben, so daß man weiß, wo man nachschauen muß, falls die Eingabe aus einem Skript kam.


8.2 Ausnahmen

Selbst wenn eine Anweisung syntaktisch korrekt ist, kann sie einen Fehler verursachen, wenn man versucht, sie auszuführen. Während des Programmablaufs festgestellte Fehler werden Ausnahmen genannt und führen nicht bedingungslos zum Abbruch des Programms. Sie werden bald lernen, sie in Python-Programmen zu handhaben. Die meisten Ausnahmen jedoch werden nicht von Programmen behandelt und resultieren in Fehlermeldungen und einem Programmabbruch wie z.B.:


>>> 10 * (1/0)
Traceback (innermost last):
  File "<stdin>", line 1
ZeroDivisionError: integer division or modulo
>>> 4 + spam*3
Traceback (innermost last):
  File "<stdin>", line 1
NameError: spam
>>> '2' + 2
Traceback (innermost last):
  File "<stdin>", line 1
TypeError: illegal argument type for built-in operation

Die letzte Zeile der Fehlermeldung erklärt, was passiert ist. Ausnahmen sind in verschiedene Typen unterteilt und der jeweilige Typ wird als Teil der Nachricht ausgegeben. Die Typen im Beispiel sind ZeroDivisionError, NameError und TypeError. Der String, der als Ausnahme-Typ ausgegeben wird, ist der Name des eingebauten Namens der aufgetretenen Ausnahme. Das gilt für alle eingebauten Ausnahmen, muß aber nicht für benutzerdefinierte Ausnahmen zutreffen (obwohl es eine nützliche Konvention ist). Standard-Ausnahme-Namen sind eingebaute Bezeichner (nicht reservierte Schlüsselworte).

Der Rest der Zeile ist ein Detail, dessen Interpretation und Bedeutung vom Ausnahme-Typen abhängen.

Der vorhergehende Teil der Fehlermeldung zeigt den Kontext, in dem der Fehler aufgetreten ist, in Form eines ,,stack backtrace`` an. Im Allgemeinen enthält er die Zeile des Quellcodes aus dem ,,stack backtrace`` es werden allerdings keine Zeilen von der Standard-Eingabe angezeigt.

Die Bibliotheks-Referenz zählt die eingebauten Ausnahmen auf und erklärt, was sie bedeuten.


8.3 Ausnahme-Behandlung

Es ist möglich, Programme zu schreiben, die ausgewählte Ausnahmen abfangen und behandeln. Betrachten Sie das folgende Beispiel, das eine Tabelle von Kehrwerten von Fließkommazahlen ausgibt:


>>> numbers = [0.3333, 2.5, 0, 10]
>>> for x in numbers:
...     print x,
...     try:
...         print 1.0 / x
...     except ZeroDivisionError:
...         print '*** has no inverse ***'
...
0.3333 3.00030003
2.5 0.4
0 *** has no inverse ***
10 0.1

Die try-Anweisung funktioniert wie folgt:

Eine try-Anweisung darf mehr als eine except-Klausel haben, um Behandlungsroutinen für verschiedene Ausnahmen zu spezifizieren. Höchstens eine Routine wird ausgeführt. Behandlungsroutinen behandeln nur Ausnahmen, die in der entsprechenden try-Klausel auftreten, nicht in anderen Behandlungsroutinen der gleichen try-Anweisung. Eine except-Klausel darf mehrere Ausnahmen in einem Tupel benennen, z.B.:


... except (RuntimeError, TypeError, NameError):
...     pass

Die letzte except-Klausel darf den (oder die) Ausnahme-Namen weglassen, um dann als Joker zu dienen. Verwenden Sie dies mit größter Vorsicht, denn es ist einfach, einen echten Programmierfehler damit auszublenden!

Die try ... except-Anweisung hat eine optionale else-Klausel, die nach allen except-Klauseln stehen muß. Sie ist nützlich als Platz für Code, der ausgeführt werden muß, wenn die try-Klausel keine Ausnahme auslöst. Beispiel:


for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except IOError:
        print 'cannot open', arg
    else:
        print arg, 'has', len(f.readlines()), 'lines'
        f.close()

Tritt eine Ausnahme auf, kann sie einen zugehörigen Wert haben, auch als Argument der Ausnahme bekannt. Das Vorhandensein und der Typ des Argumentes hängen vom Ausnahme-Typ ab. Für Ausnahme-Typen mit einem Argument darf die except-Klausel eine Variable nach dem Ausnahme-Namen (oder -Liste) spezifizieren, um den Wert des Argumentes zu erhalten. Beispiel:


>>> try:
...     spam()
... except NameError, x:
...     print 'name', x, 'undefined'
...
name spam undefined

Hat eine Ausnahme ein Argument, wird es als letzter Teil (`Detail') der Nachricht für unbehandelte Ausnahmen ausgegeben.

Ausnahme-Behandlungsroutinen behandeln Ausnahmen nicht nur, wenn sie direkt in der try-Klausel vorkommen, sondern auch, wenn sie innerhalb von Funktionen auftreten, die (sogar indirekt) in der try-Klausel aufgerufen werden, z.B.:


>>> def this_fails():
...     x = 1/0
...
>>> try:
...     this_fails()
... except ZeroDivisionError, detail:
...     print 'Handling run-time error:', detail
...
Handling run-time error: integer division or modulo


8.4 Auslösen von Ausnahmen

Die raise-Anweisung erlaubt, die Auslösung einer spezifizierten Ausnahme zu erzwingen, z.B.:


>>> raise NameError, 'HiThere'
Traceback (innermost last):
  File "<stdin>", line 1
NameError: HiThere

Das erste Argument für raise bezeichnet die Ausnahme, die ausgelöst werden soll. Das optionale zweite Argument spezifiziert ein Argument der Ausnahme.


8.5 Benutzerdefinierte Ausnahmen

Programme dürfen ihre eigenen Ausnahme-Typen erzeugen, indem ein String einer Variablen zugewiesen wird, z.B.:


>>> my_exc = 'my_exc'
>>> try:
...     raise my_exc, 2*2
... except my_exc, val:
...     print 'My exception occurred, value:', val
...
My exception occurred, value: 4
>>> raise my_exc, 1
Traceback (innermost last):
  File "<stdin>", line 1
my_exc: 1

Viele Standard-Module verwenden dies, um Fehler zu melden, die in Funktionen auftreten können, die sie definieren.


8.6 Definition von Aufräum-Aktionen

Die try-Anweisung hat eine andere optionale Klausel, die dazu gedacht ist, Aufräum-Aktionen zu definieren, die unter allen Umständen ausgeführt werden müssen, z.B.:


>>> try:
...     raise KeyboardInterrupt
... finally:
...     print 'Goodbye, world!'
...
Goodbye, world!
Traceback (innermost last):
  File "<stdin>", line 2
KeyboardInterrupt

Eine finally-Klausel wird immer ausgeführt, ob eine Ausnahme in der try-Klausel aufgetreten ist, oder nicht. Falls eine Ausnahme aufgetreten ist, wird sie erneut ausgelöst, nachdem die finally-Klausel ausgeführt wurde. Die finally-Klausel wird auch ,,auf dem Weg hinaus`` ausgeführt, wenn die try-Anweisung mit einer break- oder return-Anweisung verlassen wird.

Eine try-Anweisung muß entweder eine oder mehrere except-Klauseln oder eine finally-Klausel haben, aber nicht beides.


Send comments to python-docs@python.org.