Kapitel 12 • Schulabgleich 26.0

Exceptions & Fehlerbehandlung 🛡️🛑

Lerne, wie du Programme vor unkontrollierten Abstürzen schützt, saubere Kontrollflüsse mit try-except-else-finally baust und eigene Exception-Klassen definierst.

📂 Dateien dieser Einheit:
💻 In Web-IDE öffnen → 📄 aufgabe.py (Startercode) 🧪 test_aufgabe.py (Tests) 💡 musterloesung.py (Lösung) 📖 README.md

1. Was ist eine Exception? (Die Notbremse im Code)

In der realen Welt läuft nicht immer alles nach Plan: Eine Datei existiert nicht, der Benutzer tippt Buchstaben statt Zahlen ein, oder das Bankkonto hat nicht genug Guthaben.

🚆 Die Notbremse-Analogie:
Stelle dir einen Zug vor. Normalerweise fährt der Zug geradeaus weiter. Wenn plötzlich ein Baum auf den Schienen liegt, zieht der Lokführer die Notbremse (in Python: raise Exception()). Statt dass der Zug ungebremst entgleist (Absturz mit rotem Traceback), fängt das Rettungsteam die Situation geordnet ab (in Python: try ... except).

Typische Python-Standard-Exceptions im Überblick:

Exception-Typ Wann tritt sie auf? Beispiel
ValueError Richtiger Datentyp, aber unpassender Wert int("hallo")
TypeError Falscher Datentyp für eine Operation "Zahl: " + 5
IndexError Zugriff auf einen nicht existierenden Listen-Index liste[99]
KeyError Schlüssel in einem Dictionary nicht vorhanden dict["unbekannt"]
ZeroDivisionError Division durch die Zahl 0 10 / 0

2. Die 4 Säulen der Fehlerbehandlung

Python bietet mit try, except, else und finally eine extrem saubere Struktur, um auf jede Eventualität vorbereitet zu sein:

Struktur: try - except - else - finally
try:
    # 1. Versuche diesen Code auszuführen (kann fehlschlagen)
    eingabe = int(input("Betrag eingeben: "))
    ergebnis = 100 / eingabe

except ValueError as e:
    # 2a. Wird NUR ausgeführt, wenn ein ValueError auftrat
    print(f"Ungültige Eingabe: Keine Zahl! ({e})")

except ZeroDivisionError:
    # 2b. Wird NUR ausgeführt, wenn durch 0 geteilt wurde
    print("Division durch 0 ist nicht erlaubt!")

else:
    # 3. Wird NUR ausgeführt, wenn ALLES GLATT ging (kein Fehler)
    print(f"Erfolg! Das Ergebnis ist: {ergebnis}")

finally:
    # 4. Wird IMMER ausgeführt (egal ob Fehler oder Erfolg!)
    print("Aufräumarbeiten beendet. Vorgang abgeschlossen.")
💡 Warum finally?
finally ist perfekt für Aufräumarbeiten, die unter keinen Umständen vergessen werden dürfen – z.B. das Auswerfen der EC-Karte am Geldautomaten oder das Schließen einer offenen Datenbankverbindung!

3. Eigene Exception-Klassen definieren & werfen (raise)

In professionellen OOP-Anwendungen nutzt man nicht nur die Standard-Fehler von Python, sondern baut eigene Fehlerklassen. Dadurch weiß jeder sofort, worum es in deiner Fachdomäne geht (z.B. KontoGesperrtError statt nur ungenauem Exception).

Eigene Exception-Hierarchie
# 1. Basisklasse für alle Fehler in der Bank-Anwendung
class BankFehler(Exception):
    """Basis-Exception für alle Bank-bezogenen Probleme."""
    pass

# 2. Spezifische Fehler erben von unserer Basisklasse
class KontoGesperrtError(BankFehler):
    pass

class NichtGenugGuthabenError(BankFehler):
    pass

class UngueltigePinError(BankFehler):
    pass

Einen Fehler mit raise auslösen:

Fehler gezielt werfen
def abheben(self, betrag: float) -> float:
    if betrag > self.kontostand:
        raise NichtGenugGuthabenError(f"Nur noch {self.kontostand}€ verfügbar!")
    
    self.kontostand -= betrag
    return self.kontostand

4. 🎯 Deine Aufgaben in aufgabe.py

Öffne die Datei aufgabe.py und baue den sicheren Geldautomaten-Simulator:

💡 Lösungshinweise (Aufklappen bei Bedarf)

🔍 Tipp zur PIN-Prüfung & Fehlversuchen
if self.gesperrt:
    raise KontoGesperrtError("Konto ist gesperrt!")

if eingegebene_pin == self.pin:
    self.fehlversuche = 0
    return True
else:
    self.fehlversuche += 1
    if self.fehlversuche >= 3:
        self.gesperrt = True
        raise KontoGesperrtError("PIN 3-mal falsch. Konto wurde gesperrt!")
    raise UngueltigePinError(f"Falsche PIN! Noch {3 - self.fehlversuche} Versuche.")
🔍 Tipp zu geldautomat_abheben (try-except-else-finally)

Im try-Block rufst du einfach konto.abheben(betrag, pin) auf. Fange die verschiedenen Exception-Typen in separaten except-Blöcken ab und füge die Meldung zu deiner Liste hinzu. Im else-Block meldest du den Erfolg und im finally-Block "Bitte Karte entnehmen.".

5. 🧪 Lösung überprüfen

Führe im Terminal im Ordner 12_exceptions_und_fehlerbehandlung folgenden Befehl aus:

Terminal
python3 test_aufgabe.py