In Python sind alle Ausnahmen von der Klasse BaseException abgeleitet. Das bedeutet, dass jede Ausnahme in Python eine Instanz von BaseException oder einer ihrer Unterklassen ist.
Die BaseException-Klasse ist die oberste Klasse in der Ausnahmehierarchie. Sie bietet einige gemeinsame Methoden, die alle Ausnahmen nutzen können, wie __str__ und __repr__. Allerdings solltest du BaseException nicht direkt in deinem Code verwenden, da sie zu allgemein ist und jeden Ausnahmetyp abfangen kann. Stattdessen solltest du spezifischere Ausnahmeklassen verwenden, die Unterklassen von BaseException sind. Python stellt eine Reihe von eingebauten Ausnahmeklassen zur Verfügung, die du nutzen kannst, und du kannst auch eigene benutzerdefinierte Ausnahmeklassen erstellen:
The hierarchy of built-in exception classes in Python (from the official Python docs).
Das bedeutet, dass der FileNotFoundError eine Unterklasse von OSError ist, welche wiederum eine Unterklasse der Exception-Klasse ist, die selbst von BaseException erbt.
Beachtung der Ausnahmehierarchie
Beim Einsatz mehrerer except-Anweisungen ist es wichtig, die Ausnahmehierarchie in Python zu respektieren. Das bedeutet, wenn du eine Basisausnahmeklasse wie Exception abfängst, solltest du vorher spezifischere Ausnahmen abfangen. Wenn du eine except-Anweisung für eine spezifischere Klasse nach der Basisklasse schreibst, wird der Block nicht ausgeführt:
try:
# some code that may raise an exception
except ValueError:
# handle the ValueError
except Exception:
# handle any other exception
In diesem Beispiel wird zuerst die Ausnahme ValueError abgefangen. Wenn der Code eine andere Ausnahme auslöst, die von Exception abgeleitet ist, wird der Code im zweiten except-Block ausgeführt. Es wird jedoch nicht empfohlen, Exception direkt abzufangen, da es zu allgemein ist und jeden Ausnahmetyp erfassen kann. Es ist besser, wann immer möglich, spezifischere Ausnahmen abzufangen:
Wenn der Code im try-Block einen TypeError oder ValueError auslöst, wird der entsprechende except-Block ausgeführt. Wenn der Code eine andere Ausnahme auslöst, die von Exception abgeleitet ist, wird der Code im dritten except-Block ausgeführt.
Wenn wir die Basisausnahme als ersten except-Block platzieren, verhindert dies, dass die restlichen Blöcke jemals ausgeführt werden:
try:
# some code that may raise an exception
except Exception as e: # Dies fängt alle Fehler ab
print(f'An error occurred: {e}')
except ValueError: # Dieser Block wird nie ausgeführt
print('A ValueError occurred')
except TypeError: # Dieser Block wird nie ausgeführt
print('A TypeError occurred')
In diesem Beispiel kann der try-Block jede Art von Ausnahme auslösen. Allerdings fängt die erste except-Anweisung die Basisklasse Exception ab, sodass jede ausgelöste Ausnahme abgefangen wird. Die Fehlermeldung wird ausgegeben und die restlichen except-Anweisungen werden nicht ausgeführt.
Herausforderung: Die Datei parsen
Du arbeitest als Softwareentwickler in einem Startup, das mit großen Datenmengen arbeitet. Kürzlich hat das Team beschlossen, JSON-Dateien zur Speicherung und Verarbeitung der Daten zu verwenden. Diese Daten sind für den Betrieb deines Startups von entscheidender Bedeutung, und es ist deine Aufgabe, ein Python-Programm zu schreiben, das diese JSON-Dateien liest und parst.
Allerdings treten aufgrund der großen Datenmenge und der vielen Personen, die daran arbeiten, häufig Fehler auf:
Manchmal existiert die Datendatei nicht.
Manchmal ist die Datendatei leer.
Manchmal enthält die Datendatei Daten, die kein gültiges JSON sind.
Du musst sicherstellen, dass dein Python-Programm diese Ausnahmen handhaben kann, ohne abzustürzen, und aussagekräftige Fehlermeldungen bereitstellen, damit das Datenteam das Problem schnell identifizieren und beheben kann.
Dein Programm sollte als Eingabe einen String erhalten, der den Dateinamen repräsentiert, und die folgenden Fälle behandeln:
Wenn die Datei nicht existiert, sollte es einen FileNotFoundError auslösen und eine entsprechende Fehlermeldung ausgeben.
Wenn die Datei leer ist, sollte es einen ValueError auslösen und eine entsprechende Fehlermeldung ausgeben.
Wenn der Dateiinhalte kein gültiges JSON ist, sollte es einen json.JSONDecodeError (das ist eine Unterklasse von ValueError) auslösen und eine entsprechende Fehlermeldung ausgeben. Beim Auslösen dieser Ausnahme solltest du die Attribute doc und pos als Parameter angeben.
💡
except json.JSONDecodeError as e:
Jede dieser Ausnahmen sollte unabhängig von den anderen behandelt werden, und dein Programm sollte für jeden Fall eine spezifische Fehlermeldung bereitstellen.
Input
Output
nonexistent_file.json
FileNotFoundError: File 'nonexistent_file.json' does not exist.
empty_file.json
ValueError: File 'empty_file.json' is empty.
invalid_json.json
JSONDecodeError: Content of file 'invalid_json.json' is not valid JSON.: line 1 column 1 (char 0)
success.json
File 'success.json' has been successfully parsed as valid JSON.