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.
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.
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.
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:
... 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
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.
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.
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.