Einführung
In der Computerprogrammierung ist das Debugging der wesentliche Prozess des Auffindens und Behebens von Fehlern oder „Bugs“, die verhindern, dass ein Programm korrekt funktioniert. Obwohl Fehler ein unvermeidlicher Bestandteil der Softwareentwicklung sind, bietet Python eine leistungsstarke Reihe von Werkzeugen, die Ihnen helfen, diese effizient zu diagnostizieren und zu beheben.
In diesem Lab lernen Sie mehrere grundlegende Debugging-Techniken in Python kennen. Wir werden behandeln, wie man:
- Ausnahmen manuell auslöst und behandelt, um den Programmfluss bei Fehlern zu steuern.
- Detaillierte Fehler-Tracebacks als Zeichenketten (Strings) für Protokollierungszwecke erfasst.
- Assertions (Zusicherungen) als Plausibilitätsprüfungen verwendet, um logische Fehler frühzeitig abzufangen.
- Ein flexibles Protokollierungssystem (Logging System) implementiert, um die Ausführung Ihres Programms zu verfolgen und Probleme zu diagnostizieren, ohne dessen Ablauf zu unterbrechen.
Auslösen von Ausnahmen (Raising Exceptions)
In diesem Schritt lernen Sie, wie Sie mit der Anweisung raise manuell Ausnahmen auslösen. Ausnahmen dienen dazu, das Auftreten eines Fehlers zu signalisieren. Eine raise-Anweisung besteht aus dem Schlüsselwort raise, einem Aufruf der Funktion Exception() und einer hilfreichen Fehlermeldungszeichenkette, die an Exception() übergeben wird.
Es ist gängige Praxis, Funktionen Ausnahmen auszulösen, wenn deren Vorbedingungen nicht erfüllt sind, und diese Ausnahmen dann im aufrufenden Code mithilfe von try- und except-Blöcken zu behandeln.
Hinweis: Wenn Sie mit der WebIDE (ähnlich VS Code) nicht vertraut sind, lernen Sie diese zuerst in diesem Lab.
Versuchen wir dies anhand eines Beispiels.
- Öffnen Sie die Datei
raise_exception.pyim Dateiexplorer auf der linken Seite. - Fügen Sie den folgenden Code in die Datei ein. Dieser Code definiert eine Funktion
box_print, die Ausnahmen für ungültige Argumente auslöst, und ruft diese Funktion anschließend mit gültigen und ungültigen Eingaben auf, wobei die Ausnahmen abgefangen werden.
def box_print(symbol, width, height):
if len(symbol) != 1:
raise Exception('Symbol must be a single character string.')
if width <= 2:
raise Exception('Width must be greater than 2.')
if height <= 2:
raise Exception('Height must be greater than 2.')
print(symbol * width)
for i in range(height - 2):
print(symbol + (' ' * (width - 2)) + symbol)
print(symbol * width)
## Handle exceptions when calling the function
for sym, w, h in (('*', 4, 4), ('O', 20, 5), ('x', 1, 3), ('ZZ', 3, 3)):
try:
box_print(sym, w, h)
except Exception as err: ## Catch exception and print error message
print('An exception happened: ' + str(err))
- Führen Sie nun das Skript im Terminal aus, um zu sehen, wie die Ausnahmen ausgelöst und behandelt werden.
python3 raise_exception.py
Sie sehen die folgende Ausgabe. Die ersten beiden Aufrufe von box_print sind erfolgreich, während die letzten beiden fehlschlagen und den except-Block auslösen, um die benutzerdefinierten Fehlermeldungen auszugeben.
****
* *
* *
****
OOOOOOOOOOOOOOOOOOOO
O O
O O
O O
OOOOOOOOOOOOOOOOOOOO
An exception happened: Width must be greater than 2.
An exception happened: Symbol must be a single character string.
Den Traceback als String erhalten
Wenn eine unbehandelte Ausnahme (Exception) auftritt, gibt Python einen Traceback aus, der ein detaillierter Bericht über die Funktionsaufrufe ist, die zum Fehler geführt haben. Manchmal möchten Sie eine Ausnahme elegant behandeln, aber dennoch den vollständigen Traceback für eine spätere Fehlerbehebung aufzeichnen. Das Modul traceback ermöglicht Ihnen dies.
In diesem Schritt lernen Sie, wie Sie traceback.format_exc() verwenden, um den Traceback als Zeichenkette (String) zu erfassen und in einer Datei zu speichern.
- Öffnen Sie die Datei
get_traceback.pyim Dateiexplorer. - Fügen Sie den folgenden Code hinzu. Dieses Skript importiert das Modul
tracebackund verwendet dann einentry...except-Block, um eine Ausnahme abzufangen. Innerhalb desexcept-Blocks schreibt es den vollständigen Traceback in eine Datei namenserrorInfo.txt.
import traceback
try:
raise Exception('This is the error message.')
except:
with open('errorInfo.txt', 'w') as error_file:
error_file.write(traceback.format_exc()) ## Write traceback to file
print('The traceback info was written to errorInfo.txt.')
- Führen Sie das Skript im Terminal aus.
python3 get_traceback.py
Das Skript gibt eine Bestätigungsnachricht aus:
The traceback info was written to errorInfo.txt.
- Überprüfen Sie nun den Inhalt der neu erstellten Datei
errorInfo.txt. Sie können sie entweder über den Dateiexplorer öffnen oder den Befehlcatim Terminal verwenden.
cat errorInfo.txt
Die Datei enthält den vollständigen Traceback, ähnlich dem folgenden:
Traceback (most recent call last):
File "/home/labex/project/get_traceback.py", line 4, in <module>
raise Exception('This is the error message.')
Exception: This is the error message.
Diese Technik ist äußerst nützlich, um Fehler in Produktionsanwendungen zu protokollieren, ohne das Programm abstürzen zu lassen.
Verwendung von Assertions (Zusicherungen)
Assertions (Zusicherungen) sind Plausibilitätsprüfungen, um sicherzustellen, dass Ihr Code nichts offensichtlich Falsches tut. Eine assert-Anweisung prüft, ob eine Bedingung wahr ist. Wenn die Bedingung falsch ist, löst sie einen AssertionError aus, der idealerweise Ihr Programm zum Absturz bringen sollte. Dieser "Fail-Fast"-Ansatz hilft Ihnen, die Wurzel eines Fehlers schneller zu identifizieren.
Eine assert-Anweisung besteht aus dem Schlüsselwort assert, einer zu prüfenden Bedingung und einer optionalen Fehlermeldung.
In diesem Schritt verwenden Sie eine Assertion, um den Zustand eines Programms zu validieren.
- Öffnen Sie die Datei
use_assertions.pyim Dateiexplorer. - Fügen Sie den folgenden Code hinzu. Er überprüft den Status von
pod_bay_door_status. Die erste Assertion wird stillschweigend bestanden, aber die zweite schlägt fehl und löst einenAssertionErroraus.
## assert statement: check condition, raise AssertionError if False
pod_bay_door_status = 'open'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Passes
pod_bay_door_status = 'I\'m sorry, Dave. I\'m afraid I can\'t do that.'
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".' ## Raises AssertionError
- Führen Sie das Skript im Terminal aus.
python3 use_assertions.py
Da die zweite Assertion fehlschlägt, stürzt das Programm ab, und Sie sehen einen AssertionError mit Ihrer benutzerdefinierten Meldung.
Traceback (most recent call last):
File "/home/labex/project/use_assertions.py", line 6, in <module>
assert pod_bay_door_status == 'open', 'The pod bay doors need to be "open".'
AssertionError: The pod bay doors need to be "open".
Im Gegensatz zu Ausnahmen sollten Sie Assertions nicht mit try...except behandeln. Ein AssertionError signalisiert einen Fehler im Programm, der behoben werden muss. Es ist auch erwähnenswert, dass Assertions global deaktiviert werden können, indem Python mit dem Flag -O (optimize) ausgeführt wird. Daher sollten sie nicht für die Eingabevalidierung verwendet werden, die immer erzwungen werden muss.
Logging implementieren
Während print()-Anweisungen zum Debuggen verwendet werden können, ist der leistungsfähigere und flexiblere Ansatz die Verwendung des in Python integrierten logging-Moduls. Logging ermöglicht es Ihnen, Ereignisse während der Programmausführung zu verfolgen und Nachrichten nach Schweregrad zu kategorisieren.
In diesem Schritt fügen Sie einem Programm Logging hinzu, um bei der Diagnose eines Fehlers zu helfen.
- Öffnen Sie zuerst die Datei
factorial_log.pyim Dateiexplorer. - Fügen Sie den folgenden Code hinzu. Dieses Programm versucht, die Fakultät (factorial) einer Zahl zu berechnen, enthält aber einen Fehler. Wir haben
logging.debug()-Aufrufe hinzugefügt, um die Werte der Variablen bei jedem Schritt zu verfolgen. Die Funktionlogging.basicConfig()konfiguriert das Logging-System so, dass Nachrichten der StufeDEBUGund höher angezeigt werden.
import logging
logging.basicConfig(level=logging.DEBUG, format=' %(asctime)s - %(levelname)s - %(message)s')
logging.debug('Start of program')
def factorial(n):
logging.debug('Start of factorial(%s)' % (n))
total = 1
for i in range(1, n + 1):
total *= i
logging.debug('i is ' + str(i) + ', total is ' + str(total))
logging.debug('End of factorial(%s)' % (n))
return total
print(factorial(5))
logging.debug('End of program')
- Führen Sie das Skript im Terminal aus.
python3 factorial_log.py
Sie sehen detaillierte Log-Ausgaben, die mit der regulären Ausgabe des Programms durchsetzt sind.
%(asctime)s - DEBUG - Start of program
%(asctime)s - DEBUG - Start of factorial(5)
%(asctime)s - DEBUG - i is 1, total is 1
%(asctime)s - DEBUG - i is 2, total is 2
%(asctime)s - DEBUG - i is 3, total is 6
%(asctime)s - DEBUG - i is 4, total is 24
%(asctime)s - DEBUG - i is 5, total is 120
%(asctime)s - DEBUG - End of factorial(5)
120
%(asctime)s - DEBUG - End of program
Durch die Untersuchung der Log-Nachrichten können Sie den Wert von i und total in jeder Iteration der Schleife klar erkennen, was eine leistungsstarke Methode ist, um den Programmablauf zu verstehen und Fehler zu finden.
Logging-Verhalten konfigurieren
Das logging-Modul ist hochgradig konfigurierbar. Sie können die Schweregradstufe der anzuzeigenden Nachrichten steuern, das Logging vollständig deaktivieren oder Log-Nachrichten an eine Datei anstatt an den Bildschirm umleiten.
Logging-Stufen (Logging Levels)
Es gibt fünf Standard-Logging-Stufen, jede mit einer entsprechenden Funktion:
| Stufe | Logging-Funktion | Beschreibung |
|---|---|---|
DEBUG |
logging.debug() |
Für kleine Details, nützlich nur bei der Diagnose von Problemen. |
INFO |
logging.info() |
Zur Aufzeichnung allgemeiner Ereignisse oder zur Bestätigung, dass Dinge wie erwartet funktionieren. |
WARNING |
logging.warning() |
Um auf ein potenzielles Problem hinzuweisen, das das Programm nicht stoppt. |
ERROR |
logging.error() |
Zur Aufzeichnung eines Fehlers, der zum Fehlschlagen einer bestimmten Operation geführt hat. |
CRITICAL |
logging.critical() |
Für einen fatalen Fehler, der kurz davor steht, die Beendigung des Programms zu verursachen. |
Wenn Sie eine Logging-Stufe in basicConfig festlegen, zeigt Python Nachrichten auf dieser Stufe und allen höheren Stufen an. Wenn Sie beispielsweise level=logging.INFO festlegen, werden INFO, WARNING, ERROR und CRITICAL Nachrichten angezeigt, DEBUG jedoch nicht.
Deaktivieren des Loggings
Nach dem Debuggen möchten Sie möglicherweise alle Log-Nachrichten ausschalten, ohne die logging-Aufrufe aus Ihrem Code zu entfernen. Dies können Sie mit logging.disable() tun. Es nimmt eine Stufe als Argument entgegen und deaktiviert alle Log-Nachrichten auf dieser Stufe und darunter. Zum Beispiel unterdrückt logging.disable(logging.CRITICAL) jede Log-Nachricht.
Logging in eine Datei
Anstatt Logs auf der Konsole auszugeben, können Sie sie in einer Datei speichern, indem Sie das Schlüsselwortargument filename an logging.basicConfig() übergeben.
Üben wir dies.
- Öffnen Sie die Datei
configure_logging.py. - Fügen Sie den folgenden Code hinzu. Er konfiguriert das Logging so, dass alle Nachrichten der Stufe
DEBUGund höher in eine Datei namensmyProgramLog.txtgeschrieben werden.
import logging
## Configure logging to write to a file
logging.basicConfig(filename='myProgramLog.txt', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
logging.debug('This is a debug message.')
logging.info('This is an info message.')
logging.warning('This is a warning message.')
- Führen Sie das Skript im Terminal aus.
python3 configure_logging.py
Dieses Mal sehen Sie keine Ausgabe im Terminal.
- Überprüfen Sie den Inhalt der Datei
myProgramLog.txt.
cat myProgramLog.txt
Sie werden sehen, dass alle Log-Nachrichten mit Zeitstempeln und Schweregraden in die Datei geschrieben wurden.
2023-10-27 10:30:00,123 - DEBUG - This is a debug message.
2023-10-27 10:30:00,123 - INFO - This is an info message.
2023-10-27 10:30:00,123 - WARNING - This is a warning message.
Dies beendet unsere Einführung in grundlegende Python-Debugging-Techniken.
Zusammenfassung
In diesem Lab haben Sie mehrere wesentliche Python-Debugging-Techniken gelernt und geübt. Sie begannen damit, die raise-Anweisung zu verwenden, um benutzerdefinierte Ausnahmen (Exceptions) zu erstellen und auszulösen, und diese mit try...except-Blöcken zu behandeln. Anschließend lernten Sie, wie man einen vollständigen Ausnahme-Traceback als String mithilfe von traceback.format_exc() für Logging-Zwecke erfasst.
Danach haben Sie assert-Anweisungen als Mittel zur Durchführung von Plausibilitätsprüfungen (Sanity Checks) und zum "schnellen Fehlschlagen" (fail fast) untersucht, wenn Ihr Programm in einen unerwarteten Zustand gerät. Schließlich haben Sie sich mit dem logging-Modul beschäftigt und gelernt, wie man es konfiguriert, um Nachrichten anzuzeigen, die Ausgabe mit verschiedenen Logging-Stufen zu steuern und Logs zur dauerhaften Speicherung in eine Datei zu schreiben.
Diese Fähigkeiten sind grundlegend für das Schreiben robuster, wartbarer und leichter zu debuggender Python-Anwendungen.



