141 lines
5.3 KiB
Python
141 lines
5.3 KiB
Python
"""
|
|
Kapitel 12: Exceptions & Fehlerbehandlung 🛡️🛑
|
|
=============================================
|
|
Musterlösung für die Bankkonto- und Geldautomat-Simulation.
|
|
"""
|
|
|
|
from typing import Optional
|
|
|
|
|
|
# ==============================================================================
|
|
# 1. Eigene Exception-Hierarchie
|
|
# ==============================================================================
|
|
class BankFehler(Exception):
|
|
"""Basisklasse für alle Fehler im Bankkonto-System."""
|
|
pass
|
|
|
|
|
|
class UngueltigePinError(BankFehler):
|
|
"""Wird geworfen, wenn die eingegebene PIN falsch ist."""
|
|
pass
|
|
|
|
|
|
class KontoGesperrtError(BankFehler):
|
|
"""Wird geworfen, wenn das Konto gesperrt ist (oder nach 3 Fehlversuchen gesperrt wird)."""
|
|
pass
|
|
|
|
|
|
class NichtGenugGuthabenError(BankFehler):
|
|
"""Wird geworfen, wenn das Guthaben für eine Abhebung nicht ausreicht."""
|
|
pass
|
|
|
|
|
|
class UngueltigerBetragError(BankFehler):
|
|
"""Wird geworfen, wenn ein ungültiger (z.B. <= 0) Betrag übergeben wird."""
|
|
pass
|
|
|
|
|
|
# ==============================================================================
|
|
# 2. Klasse Bankkonto
|
|
# ==============================================================================
|
|
class Bankkonto:
|
|
def __init__(self, inhaber: str, pin: str, kontostand: float = 0.0):
|
|
"""Initialisiert ein Bankkonto mit Inhaber, PIN und Startguthaben."""
|
|
if kontostand < 0:
|
|
raise UngueltigerBetragError("Der Anfangskontostand darf nicht negativ sein!")
|
|
self.inhaber: str = inhaber
|
|
self.pin: str = pin
|
|
self.kontostand: float = float(kontostand)
|
|
self.gesperrt: bool = False
|
|
self.fehlversuche: int = 0
|
|
|
|
def pin_pruefen(self, eingegebene_pin: str) -> bool:
|
|
"""Prüft die PIN, zählt Fehlversuche und sperrt ggf. das Konto."""
|
|
if self.gesperrt:
|
|
raise KontoGesperrtError(f"Das Konto von {self.inhaber} 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 eingegeben! Das Konto wurde aus Sicherheitsgründen gesperrt.")
|
|
raise UngueltigePinError(f"Falsche PIN! Verbleibende Versuche: {3 - self.fehlversuche}")
|
|
|
|
def einzahlen(self, betrag: float) -> float:
|
|
"""Zahlt Geld auf das Konto ein."""
|
|
if self.gesperrt:
|
|
raise KontoGesperrtError(f"Das Konto von {self.inhaber} ist gesperrt!")
|
|
if betrag <= 0:
|
|
raise UngueltigerBetragError("Einzahlungsbetrag muss größer als 0 sein!")
|
|
self.kontostand += betrag
|
|
return self.kontostand
|
|
|
|
def abheben(self, betrag: float, pin: str) -> float:
|
|
"""Hebt Geld nach erfolgreicher PIN- und Guthabenprüfung ab."""
|
|
# 1. PIN & Sperre prüfen (wirft automatisch passende Fehler)
|
|
self.pin_pruefen(pin)
|
|
|
|
# 2. Betrag prüfen
|
|
if betrag <= 0:
|
|
raise UngueltigerBetragError("Abhebebetrag muss größer als 0 sein!")
|
|
|
|
# 3. Deckung prüfen
|
|
if betrag > self.kontostand:
|
|
raise NichtGenugGuthabenError(f"Nicht genug Guthaben! Verfügbar: {self.kontostand:.2f}€, Angefordert: {betrag:.2f}€")
|
|
|
|
self.kontostand -= betrag
|
|
return self.kontostand
|
|
|
|
def sperren(self) -> None:
|
|
"""Sperrt das Konto manuell."""
|
|
self.gesperrt = True
|
|
|
|
def entsperren(self, admin_passwort: str) -> bool:
|
|
"""Entsperrt das Konto bei korrektem Admin-Passwort."""
|
|
if admin_passwort == "ADMIN123":
|
|
self.gesperrt = False
|
|
self.fehlversuche = 0
|
|
return True
|
|
raise UngueltigePinError("Falsches Admin-Passwort zum Entsperren!")
|
|
|
|
def __str__(self) -> str:
|
|
"""String-Repräsentation des Kontos."""
|
|
status = "GESPERRT" if self.gesperrt else "AKTIV"
|
|
return f"Bankkonto({self.inhaber}, Stand: {self.kontostand:.2f}€, Status: {status})"
|
|
|
|
|
|
# ==============================================================================
|
|
# 3. Geldautomat mit vollständiger try-except-else-finally-Struktur
|
|
# ==============================================================================
|
|
def geldautomat_abheben(konto: Bankkonto, betrag: float, pin: str) -> str:
|
|
"""Führt eine sichere Abhebung mit try-except-else-finally durch."""
|
|
meldungen = []
|
|
try:
|
|
konto.abheben(betrag, pin)
|
|
except UngueltigePinError as e:
|
|
meldungen.append(f"PIN-Fehler: {e}")
|
|
except KontoGesperrtError as e:
|
|
meldungen.append(f"Sicherheits-Fehler: {e}")
|
|
except NichtGenugGuthabenError as e:
|
|
meldungen.append(f"Deckungs-Fehler: {e}")
|
|
except UngueltigerBetragError as e:
|
|
meldungen.append(f"Betrags-Fehler: {e}")
|
|
except BankFehler as e:
|
|
meldungen.append(f"Bank-Fehler: {e}")
|
|
else:
|
|
meldungen.append(f"Auszahlung erfolgreich: {betrag:.2f}€ ausgezahlt. Neuer Stand: {konto.kontostand:.2f}€")
|
|
finally:
|
|
meldungen.append("Bitte Karte entnehmen.")
|
|
|
|
return " | ".join(meldungen)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
konto = Bankkonto("Anna", "1234", 250.0)
|
|
print(konto)
|
|
print(geldautomat_abheben(konto, 50.0, "1234"))
|
|
print(geldautomat_abheben(konto, 50.0, "9999"))
|
|
print(geldautomat_abheben(konto, 500.0, "1234"))
|