Fehleranalyse#
IPython enthält verschiedene Werkzeuge, um fehlerhaften Code zu analysieren, im Wesentlichen das Exception Reporting und den Debugger.
Exceptions kontrollieren mit %xmode
#
Wenn die Ausführung eines Python-Skripts fehlschlägt, wird meist eine sog. Exception ausgelöst und relevante Informationen zur Fehlerursache in einen Traceback geschrieben. Mit der %xmode
-Magic-Funktion könnt ihr in IPython die Menge der Informationen steuern, die euch angezeigt werden. Betrachten wir hierfür den folgenden Code:
[1]:
def func1(a, b):
return a / b
def func2(x):
a = x
b = x - 1
return func1(a, b)
[2]:
func2(1)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-2-7cb498ea7ed1> in <module>
----> 1 func2(1)
<ipython-input-1-586ccabd0db3> in func2(x)
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
<ipython-input-1-586ccabd0db3> in func1(a, b)
1 def func1(a, b):
----> 2 return a / b
3
4 def func2(x):
5 a = x
ZeroDivisionError: division by zero
Der Aufruf von func2
führt zu einem Fehler, und der Traceback
zeigt genau, was passiert ist: in jeder Zeile wird der Kontext jedes Schritts angezeigt, der schließlich zum Fehler geführt hat. Mit der %xmode
-Magic-Funktion (kurz für Exception-Modus) können wir steuern, welche Informationen uns angezeigt werden sollen.
%xmode
nimmt ein einziges Argument, den Modus, und es gibt drei Möglichkeiten: * Plain
* Context
* Verbose
Die Standardeinstellung ist Context
und gibt eine Ausgabe wie die obige aus. Plain
ist kompakter und liefert weniger Informationen:
[3]:
%xmode Plain
func2(1)
Exception reporting mode: Plain
Traceback (most recent call last):
File "<ipython-input-3-2c0c65acd0a8>", line 2, in <module>
func2(1)
File "<ipython-input-1-586ccabd0db3>", line 7, in func2
return func1(a, b)
File "<ipython-input-1-586ccabd0db3>", line 2, in func1
return a / b
ZeroDivisionError: division by zero
Der Verbose
-Modus zeigt einige zusätzliche Informationen an, einschließlich der Argumente für alle aufgerufenen Funktionen:
[4]:
%xmode Verbose
func2(1)
Exception reporting mode: Verbose
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-4-180acea4108b> in <module>
1 get_ipython().run_line_magic('xmode', 'Verbose')
----> 2 func2(1)
global func2 = <function func2 at 0x106312a60>
<ipython-input-1-586ccabd0db3> in func2(x=1)
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
global func1 = <function func1 at 0x1063129d8>
a = 1
b = 0
<ipython-input-1-586ccabd0db3> in func1(a=1, b=0)
1 def func1(a, b):
----> 2 return a / b
a = 1
b = 0
3
4 def func2(x):
5 a = x
ZeroDivisionError: division by zero
Diese zusätzlichen Informationen können helfen, den Grund für die Exception einzugrenzen. Umgekehrt kann der Verbose
-Modus jedoch bei komplexem Code zu extrem langen Tracebacks führen, bei denen kaum noch die wesentlichen Stellen erkannt werden können.
Debugging#
Wenn durch das Lesen eines Traceback
ein Fehler nicht gefunden werden kann, hilft Debugging weiter. Der Python-Standard für interaktives Debugging ist der Python-Debugger pdb
. Mit ihm könnt ihr euch zeilenweise durch den Code navigieren, um festzustellen, was möglicherweise einen Fehler verursacht. Die erweiterte Version für IPython ist ipdb
.
In IPython ist der %debug
-Magic-Befehl möglicherweise die bequemste Art zum Debugging. Wenn ihr ihn aufruft, nachdem eine Exception ausgegeben wurde, wird automatisch ein interaktiver Debug-Prompt während der Exception geöffnet. Mit der ipdb
-Eingabeaufforderung könnt ih den aktuellen Status des Stacks untersuchen, die verfügbaren Variablen untersuchen und sogar Python-Befehle ausführen.
Schauen wir uns die letzte Exception an und führen dann einige grundlegende Aufgaben aus:
[5]:
%debug
> <ipython-input-1-586ccabd0db3>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
4 def func2(x):
5 a = x
ipdb> print(a)
1
ipdb> print(b)
0
ipdb> quit
Der interaktive Debugger bietet jedoch viel mehr – wir können im Stack auch auf und ab gehen und die Werte von Variablen untersuchen:
[6]:
%debug
> <ipython-input-1-586ccabd0db3>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
4 def func2(x):
5 a = x
ipdb> up
> <ipython-input-1-586ccabd0db3>(7)func2()
3
4 def func2(x):
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
ipdb> print(x)
1
ipdb> up
> <ipython-input-4-180acea4108b>(2)<module>()
1 get_ipython().run_line_magic('xmode', 'Verbose')
----> 2 func2(1)
ipdb> down
> <ipython-input-1-586ccabd0db3>(7)func2()
3
4 def func2(x):
5 a = x
6 b = x - 1
----> 7 return func1(a, b)
ipdb> quit
Dies vereinfacht die Suche nach den Funktionsaufrufen, die zum Fehler geführt haben, enorm.
Wenn der Debugger automatisch gestartet werden soll, wenn eine Ausnahme ausgelöst wird, könnt ihr die %pdb
-Magic-Funktion verwenden, um dieses Verhalten zu aktivieren:
[7]:
%xmode Plain
%pdb on
func2(1)
Exception reporting mode: Plain
Automatic pdb calling has been turned ON
Traceback (most recent call last):
File "<ipython-input-7-f80f6b5cecf3>", line 3, in <module>
func2(1)
File "<ipython-input-1-586ccabd0db3>", line 7, in func2
return func1(a, b)
File "<ipython-input-1-586ccabd0db3>", line 2, in func1
return a / b
ZeroDivisionError: division by zero
> <ipython-input-1-586ccabd0db3>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
4 def func2(x):
5 a = x
ipdb> print(b)
0
ipdb> quit
Wenn ihr ein Skript habt, das ihr von Anfang an im interaktiven Modus ausführen möchtet, so könnt ihr dies mit dem Befehl %run -d
.
Wesentliche Befehle des ipdb
#
Befehl |
Beschreibung |
---|---|
|
Zeige den aktuellen Ort in der Datei |
|
Liste der Befehle anzeigen oder Hilfe zu einem bestimmten Befehl suchen |
|
Beendet den Debugger und das Programm |
|
Den Debugger beenden, im Programm fortfahren |
|
Gehe zum nächsten Schritt des Programms |
|
Wiederhole den vorherigen Befehl |
|
Druckvariablen |
|
Schritt in eine Unterroutine |
|
Rückkehr aus einem Unterprogramm |
Weitere Informationen zum IPython-Debugger erhaltet ihr unter ipdb.