Kurs
Wenn Python-Code während der Ausführung Probleme hat, löst er oft eine Ausnahme aus. Wenn du Ausnahmen nicht abfängst, stürzt dein Programm ab. Mit „ try-except
“-Blöcken kannst du sie aber abfangen, problemlos wiederherstellen und deine Anwendung am Laufen halten.
In diesem Tutorial geht's nicht um die Grundlagen von Ausnahmen, das haben wir schon in unserem Anleitung „Ausnahme- und Fehlerbehandlung in Python“behandelt. Stattdessen schauen wir uns hier mal genauer an, wie man „ try-except
“ in der Praxis anwendet: wie man Blöcke strukturiert, häufige Fehler vermeidet und bewährte Methoden anwendet, die den Code in echten Szenarien zuverlässiger machen.
Am Ende wirst du nicht nur wissen, wie „ try-except
” funktioniert, sondern auch, wie man es auf die Python-typische Art nutzt, indem du Fehlerbehandlungscode schreibst, der klar, wartbar und produktionsreif ist.
Wenn du noch dabei bist, Python zu lernen, schau dir doch mal den Lernpfad „Python Programming Fundamentals“, der dir dabei hilft, alle wichtigen Fähigkeiten zu entwickeln.
Warum den Fokus auf try-except legen?
Bei der Fehlerbehandlung in Python geht's im Grunde darum, Programme zu entwickeln, die mit unerwarteten Situationen klarkommen. Und obwohl es viele Tools für die Fehlerbehandlung gibt, ist „ try-except
“ das Rückgrat des Python-Ansatzes.
Warum ist das so wichtig?
- Das spiegelt die Philosophie von Python wider. In Python ist der gängige Stil„ “ (EAFP – Easier to Ask Forgiveness than Permission, „Es ist einfacher, um Vergebung zu bitten als um Erlaubnis“).. Anstatt alles vorher zu checken (gibt's diese Datei? Ist diese Eingabe okay? Ist der Server da?), probierst du die Aktion einfach aus. Wenn es nicht klappt, fängst du die Ausnahme ab und kümmerst dich darum. Das macht den Code kürzer und übersichtlicher.
- Es sorgt dafür, dass der Code in echten Umgebungen läuft. Benutzereingaben werden chaotisch sein, Dateien werden verloren gehen, APIs werden abstürzen und Netzwerke werden ausfallen. Mit „
try-except
” kannst du Code schreiben, der nicht beim ersten Problem zusammenbricht, sondern clever reagiert. - Es ist flexibel genug für Anfänger und Profis. Ein Anfänger könnte „
try-except
“ verwenden, um einen „ValueError
“ beim Umwandeln der Eingabe in eine Ganzzahl abzufangen. Ein Produktionssystem kann es nutzen, um Fehler zu protokollieren, fehlgeschlagene Vorgänge zu wiederholen oder benutzerdefinierte Ausnahmen auszulösen, die das Debuggen einfacher machen.
Deshalb geht's in diesem Artikel um „ try-except
“. Wenn du das draufhast, ist das der Unterschied zwischen Skripten, die nur unter perfekten Bedingungen funktionieren, und Software, die robust, wartungsfreundlich und einsatzbereit ist.
Aufbau eines Try-Except-Blocks
Ganz einfach gesagt:
try:
risky_thing()
except SomeError:
handle_it()
Wenn Python im Block „ try
“ auf einen Fehler stößt, springt es zum passenden Block „ except
“, anstatt das Programm zum Absturz zu bringen.
Du kannst dieses Muster auch mit den Klauseln „ else
“ und „ finally
“ erweitern:
try:
do_something()
except ValueError:
print("Bad value!")
else:
print("All good.")
finally:
clean_up()
Hier ist ein einfaches Beispiel, das funktioniert:
try:
x = int(input("Enter a number: "))
except ValueError:
print("That wasn’t a number.")
else:
print("You entered", x)
finally:
print("Done.")
Die Funktion „ except
” kümmert sich um den Fehler, „else” läuft nur, wenn alles geklappt hat, und „finally” läuft immer, auch wenn du Strg+C drückst oder das Programm beendest.
Umgang mit mehreren Ausnahmen
Manchmal reicht ein einziger „ except
“ einfach nicht aus. Verschiedene Codepfade können auf unterschiedliche Weise schiefgehen, und alles Mögliche mit einem bloßen „except“ abzufangen, ist nicht gerade hilfreich; es kann Fehler verstecken und das Debuggen zu einer echten Herausforderung machen.
Angenommen, du versuchst, etwas in eine ganze Zahl umzuwandeln und dann zu dividieren. Hier ist, was dunicht machen solltest:
try:
result = int(user_input) / 2
except:
print("Something went wrong.")
Das fängt alles, auch Sachen, die du wahrscheinlich gar nicht verstecken wolltest, wie Tippfehler in Variablennamen oder unerwartete Ausnahmen, die auf echte Probleme hinweisen.
Sei lieber konkret:
try:
result = int(user_input) / 2
except ValueError:
print("That wasn't a number.")
except ZeroDivisionError:
print("Division by zero?")
Wenn du mehrere Ausnahmetypen hast, die gleich behandelt werden sollen, kannst du sie wie folgt gruppieren:
try:
result = some_function()
except (TypeError, ValueError):
print("Something was wrong with the data.")
So weißt du immer noch genau, was schiefgehen könnte, ohne denselben Block immer wieder zu wiederholen.
Und dann gibt's noch except Exception
, das zwar besser ist als das bloße except
, aber immer noch ein bisschen zu breit. Du solltest dich lieber auf die spezifischen Fehler konzentrieren, die du erwartest.
Verwendung von else- und finally-Blöcken
Wenn der Code im Block „ try
“ erfolgreich ist und keine Ausnahmen ausgelöst werden, führt Python den Block „ else
“ aus.
try:
user_id = get_user_id()
except LookupError:
print("User not found.")
else:
print("Welcome, user", user_id)
So kannst du deine Logik zur Ausnahmebehandlung vom Happy Path trennen, was die Lesbarkeit verbessert.
Dann gibt's noch „ finally
“. Es ist egal, was passiert ist; es läuft einfach, egal was passiert. Ausnahme? Läuft immer noch. Keine Ausnahme? Läuft immer noch. Das Programm stürzt mit Strg-C ab? Läuft immer noch. Super zum Aufräumen:
try:
f = open("data.txt")
process(f)
except IOError:
print("Couldn’t open file.")
finally:
f.close()
Denk einfach dran: Wenn die Datei nie geöffnet wurde, gibt es „ f
“ vielleicht gar nicht, also pass auf. Du kannst stattdessen den Kontextmanager von Python (with open(...) as f:
) verwenden, wenn du mit Dateien arbeitest. Es ist sicherer.
Wenn du wichtige Techniken wie Ausnahmebehandlung und Fehlervermeidung lernen möchtest, um die Ausnahme „ KeyError
“ in Python effektiv zu behandeln, empfehle ich dir unsere Tutorial „Python KeyError-Ausnahmen und wie man sie behebt” Tutorial.
Python try-except: Bewährte Methoden und häufige Fallstricke
Mal ehrlich: Das Schreiben von „ try‑except
“-Blöcken ist echt eine Kunst für sich. Wenn man es richtig macht, verhindern sie, dass dein Programm abstürzt. Wenn das schlecht gemacht wird, verstecken sie Fehler so gut, dass du sie erst merkst, wenn deine App abstürzt und die Nutzer sich beschweren.
Hier sind ein paar Gewohnheiten, die du dir aneignen solltest:
Halt die „ try
“-Blöcke fest. Pack nicht hundert Zeilen Code in einen einzigen try-Block. Das macht es nur noch schwieriger, rauszufinden, was das Problem verursacht hat. Pack stattdessen nur den Code ein, der vielleicht nicht klappt:
# Good
try:
value = int(data)
except ValueError:
print("Couldn’t convert.")
# Bad
try:
# Tons of unrelated logic
value = int(data)
do_more()
something_else()
except ValueError:
print("Huh?")
Vermeide es, Bedingungen vor der Ausführung der Aktion zu überprüfen, wenn es einfacher ist, einfach zu versuchen, den Fehler abzufangen. Python hat dafür einen Namen: EAFP, Es ist einfacher, um Vergebung zu bitten als um Erlaubnis. Wenn du überprüfst, ob eine Datei da ist, und sie dann öffnest, verursachst du eine Race Condition. Instead:
try:
with open("file.txt") as f:
content = f.read()
except FileNotFoundError:
print("No file.")
Dieses Muster verhindert ein häufiges Problem, bei dem die Datei zwischen der Überprüfung und dem Öffnen verschwinden könnte. Probier's einfach mal aus. Wenn es nicht klappt, fang den Fehler ab.
Vermeide es auch, Fehler zu ignorieren, indem du alles abfängst und nichts machst. Mach das nicht:
try:
something()
except:
pass
Wenn du nicht wirklich weißt, was du tust, verstecken sich hier Fehler und vermehren sich. Wenn du jemanden zum Schweigen bringen musst, sei konkret:
try:
something()
except TimeoutError:
# okay to ignore in this case
pass
Und die Fehler irgendwo protokollieren. Wenn du sie komplett schluckst, wirst du später keine Ahnung haben, was schiefgelaufen ist.
Eingebaute vs. benutzerdefinierte Ausnahmen
Python hat viele eingebaute Ausnahmen, die echt viele Fälle abdecken. Du bist wahrscheinlich schon auf einige gestoßen:
ValueError
Wenn etwas den richtigen Typ, aber einen ungültigen Wert hat, wie zum Beispiel „int("hello")
“.TypeError
Wenn du versuchst, eine Operation auf den falschen Typ anzuwenden, wie zum Beispiel das Addieren einer Zeichenfolge und einer Zahl.ZeroDivisionError
Du hast es erraten: Division durch Null.FileNotFoundError
Ich versuche, eine Datei zu öffnen, die nicht da ist.KeyError
Wenn ein Schlüssel in einem Wörterbuch fehlt.
Die sind echt praktisch und reichen in den meisten Skripten oder Apps total aus. Manchmal willst du aber vielleicht was Beschreibenderes ansprechen, was in deinem Projekt Sinn macht, nicht nur in Python.
Angenommen, du entwickelst eine App, die Online-Bestellungen bearbeitet, und möchtest eine Fehlermeldung ausgeben, wenn ein Nutzer versucht, einen Artikel zu kaufen, der nicht vorrätig ist. Du könntest einfach „ ValueError
“ nehmen, aber das ist ein bisschen zu allgemein. Es sagt dem nächsten, der deinen Code liest, nicht, was passiert ist.
Hier kommen benutzerdefinierte Ausnahmen richtig gut rüber.
class OutOfStockError(Exception):
pass
def check_inventory(product_id):
if not in_stock(product_id):
raise OutOfStockError(f"Product {product_id} is out of stock.")
Durch das Erstellen der benutzerdefinierten Ausnahme fügst du eine Bedeutungsebene hinzu. Du gibst dir auch mehr Kontrolle; du kannst genau diese eine bestimmte Situation erfassen:
try:
check_inventory("shirt-001")
except OutOfStockError:
print("Sorry, that item is sold out.")
Es ist nur eine Kleinigkeit, aber es macht deinen Code einfacher zu verstehen und zu pflegen, vor allem bei größeren Projekten. Und es funktioniert gut mit Protokollierung und Überwachung. Benutzerdefinierte Ausnahmenamen sind viel einfacher zu finden als ein vager „ ValueError
“.
Protokollierung, erneutes Auslösen und Ausnahmeketten
Beim Debuggen gibt's diesen Moment: Du siehst einen Traceback, starrst ihn an und merkst, dass du keine Ahnung hast, warum etwas schiefgelaufen ist. Hier kommt die Holzgewinnung ins Spiel. Es geht nicht nur darum, Fehler festzuhalten, sondern auch darum, deinem zukünftigen Ich (oder deinem Team) Hinweise zu geben, um herauszufinden, was schiefgelaufen ist.
Angenommen, du fängst eine Ausnahme ab und möchtest sie protokollieren, bevor du fortfährst:
import logging
logging.basicConfig(level=logging.ERROR)
try:
do_something()
except ValueError as e:
logging.error("Failed to do something: %s", e)
raise
Das „ raise
“ am Ende ist wichtig, weil es die gleiche Ausnahme nach der Protokollierung erneut auslöst. Ohne das hast du den Fehler einfach geschluckt. Manchmal ist das okay, aber meistens ist es das nicht.
Dann gibt's noch den „ raise from
“-Trick. Das ist nützlich, wenn du einen Fehler bearbeitest, aber einen anderen auslösen musst und den ursprünglichen nicht verlieren willst. Mit Python kannst du sie verketten:
try:
connect_to_database()
except TimeoutError as e:
raise ConnectionError("Database unavailable.") from e
So zeigt der Traceback die ganze Geschichte. Du bekommst die neue Version „ ConnectionError
“, siehst aber auch die Version „ TimeoutError
“, die das verursacht hat.
Du kannst auch den ursprünglichen Fehler unterdrücken (was du normalerweise nicht tun solltest), und zwar so:
raise ConnectionError("Just this error, nothing else.") from None
Aber wenn du keinen guten Grund hast, hilft es allen, die ganze Kette zu behalten, um zu verstehen, was schiefgelaufen ist und wie es zu dieser Lawine gekommen ist.
Die Grundlagen der Protokollierung in Python kannst du in unserem Tutorial „Protokollierung in Python”.
Beispiele aus der Praxis und Anwendungsfälle
Es ist eine Sache, abstrakt über die Behandlung von Ausnahmen zu reden, aber es macht erst richtig Sinn, wenn man es im echten Code sieht.
Nimm zum Beispiel Benutzereingaben. Frag einfach jeden, der schon mal ein Befehlszeilentool oder einen Formularvalidator entwickelt hat: Nutzer geben die seltsamsten Sachen ein. Du fragst nach einer Nummer? Jemand wird „zwölf“ eingeben. Oder gib einfach eine Telefonnummer ein. Oder drück einfach die Eingabetaste. Das kommt vor.
Anstatt eine lange Liste mit „Was-wäre-wenn“-Prüfungen zu schreiben, kannst du Folgendes machen:
while True:
user_input = input("Enter a number: ")
try:
number = int(user_input)
break
except ValueError:
print("Try again with a whole number.")
Dieser Code flippt nicht aus, wenn er irgendwelchen Müll als Eingabe kriegt. Es sagt dem Benutzer, er soll's nochmal versuchen, und wiederholt das, bis alles gut aussieht. Viel übersichtlicher als wenn man für jeden Sonderfall if-Anweisungen stapeln würde.
Hier ist noch was: aus einer Datei lesen, die vielleicht gar nicht da ist.
try:
with open("config.json") as f:
settings = f.read()
except FileNotFoundError:
print("Missing config file. Using defaults.")
settings = "{}"
Du musst nicht nachsehen, ob die Datei da ist. Versuch einfach, es zu öffnen, und wenn's nicht klappt, mach weiter. Wenn du vorher nachgesehen hättest (os.path.exists()
), hätte jemand anderes die Datei zwischen dem Nachsehen und dem Öffnen vielleicht gelöscht. Das ist eine Race Condition, die du nicht debuggen solltest.
Netzwerkanfragen sind auch eine Goldgrube für Ausnahmen. Du kannst dich nicht immer darauf verlassen, dass das Internet sich benimmt. Die Server fallen aus. Die Verbindungen brechen ab. DNS funktioniert nicht. Also, wenn du so was machst:
import requests
try:
response = requests.get("https://example.com/data")
response.raise_for_status()
except requests.exceptions.RequestException as e:
print("Network problem:", e)
Die Basisklasse „ RequestException
“ fängt praktisch alles ab, was „ requests
“ auslösen könnte, von Zeitüberschreitungen bis hin zu fehlerhaften Antworten. Du musst nicht zehn verschiedene „ except
“-Blöcke schreiben, es sei denn, du willst sie unterschiedlich behandeln.
Und wenn du Automatisierungsskripte oder Backend-Dienste schreibst, kann das Einbinden wichtiger Logik in Try-Except-Blöcke den Unterschied zwischen dem Scheitern einer einzelnen Aufgabe und dem Ausfall des gesamten Systems ausmachen. Du willst, dass Fehler protokolliert werden, wiederherstellbare Aufgaben erneut versucht werden und nicht wiederherstellbare Aufgaben sauber beendet werden, ohne dass kryptische Stapelverfolgungen endlos durch deine Protokolle scrollen.
Lerne mehr über Python-Automatisierung, einschließlich grundlegender Konzepte, wichtiger Bibliotheken, der Arbeit mit Daten, der Verwendung von KI-Erweiterungen und Best Practices aus unserem Kurs „ Python Automation“: Ein kompletter Leitfaden zum Tutorial „ “.
Try-except Python Fortgeschrittene Anwendungen
Mittlerweile hast du bestimmt schon gesehen, wie flexibel try‑except
sein kann. Aber Flexibilität hat zwei Seiten. Man kann schnell von hilfsbereit zu schlampig werden, ohne es zu wollen. Hier erfährst du, wie du alles im Griff behältst.
Bestimmte Ausnahmen abfangen. Wenn du weißt, was schiefgehen könnte, sag es einfach:
try:
result = int(data)
except ValueError:
# Only catches invalid numbers, not everything else under the sun
Vermeide bloße except
:. Mach das nur, wenn du was ganz Besonderes machst. Es fängt Sachen wie „ KeyboardInterrupt
“, „ SystemExit
“ und andere Dinge ab, die du wahrscheinlich nicht stumm schalten willst.
Benutz else
und finally
, wenn sie den Code klarer machen. Bring sie nicht einfach rein, nur weil es sie gibt. Wenn dein Code in der Regel in einer Funktion „ try
” steckt, kannst du ihn vielleicht in eine Funktion „ else
” verschieben.
Mach deine „ try
“-Blöcke klein. Je mehr du einbaust, desto schwieriger wird es, rauszufinden, welche Zeile den Fehler verursacht hat. Wickle nur den Teil ein, der kaputtgehen könnte.
Protokollier Fehler, wenn's nötig ist, vor allem in der Produktion. Auch wenn du keinen Absturz hast, macht es das Debuggen später viel einfacher, wenn du weißt, was (und wann) schiefgelaufen ist.
Benutzerdefinierte Ausnahmen sind nicht zwingend nötig, aber sie sind echt hilfreich. Wenn du Probleme mit einer bestimmten App hast, definiere deine eigenen Fehler. Sie können Protokolle übersichtlicher und deinen Code selbsterklärender machen.
Noch eins: Benutze Ausnahmen nicht für die Ablaufsteuerung, es sei denn, es gibt keine bessere Lösung. Es ist verlockend, Logik wie „versuche dies; wenn es nicht klappt, mach das“ zu schreiben, aber wenn du davon ausgehst, dass das ständig passiert, gibt es wahrscheinlich eine sauberere Lösung.
Fazit
Wie ich in diesem Artikel erklärt habe, geht es bei der Ausnahmebehandlung nicht nur darum, Abstürze zu vermeiden. Es geht darum, Code zu schreiben, der Probleme erwartet, sie ohne Drama löst und weiterläuft oder auf sinnvolle Weise herunterfährt. Es ist der Unterschied zwischen einer hilfreichen Meldung für den Benutzer und einer langen, unlesbaren Fehlermeldung, die ihn zurück zum Terminal schickt.
Ich empfehle dir echt, mehr über Ausnahmen zu lernen, mit ein paar praktischen Übungen in unserem Ausnahmen in Python abfangen unseres Kurses „OOP in Python” mehr über Ausnahmen zu lernen.
Python try-except FAQs
Was ist der Unterschied zwischen einem Fehler und einer Ausnahme in Python?
Ein Fehler ist meistens ein Problem, das Python daran hindert, deinen Code überhaupt zu starten, wie zum Beispiel ein fehlender Doppelpunkt oder ein Tippfehler in einem Schlüsselwort. Das sind Syntaxfehler. Während der Ausführung des Codes passiert ein Fehler, zum Beispiel beim Versuch, durch Null zu teilen oder eine Datei zu öffnen, die nicht da ist. Ausnahmen können abgefangen und behandelt werden, damit dein Programm nicht abstürzt.
Ist es schlecht, in Python ein bloßes „except“ zu benutzen?
Ja, meistens schon. Ein bloßes ` except
` fängt alles ab, auch Sachen, die du gar nicht abfangen wolltest, wie Tastaturunterbrechungen oder Systembeendigungssignale. Das macht das Debuggen schwierig. Es ist besser, bestimmte Ausnahmen abzufangen, wie z. B. „ ValueError
“ oder „ FileNotFoundError
“, damit du genau weißt, womit du es zu tun hast.
Wann sollte ich „else“ in einem „try-except“-Block verwenden?
Benutz „else“, wenn du einen Code nur ausführen willst, wenn im „try“-Block keine Ausnahme passiert ist. Das hilft dir dabei, die Logik für den Erfolgspfad von der Logik für die Fehlerbehandlung zu trennen, was deinen Code leichter lesbar und wartbar macht.
Was bringt „finally“, wenn ich schon einen „except“-Block hab?
finally
läuft immer, egal ob ein Fehler auftritt oder nicht. Es ist super zum Aufräumen: Dateien schließen, Ressourcen freigeben, Transaktionen rückgängig machen und so weiter. Auch wenn ein Fehler auftritt oder du das Programm vorzeitig beendest, wird es trotzdem ausgeführt.
Sollte ich immer „try-except“ verwenden, anstatt zuerst die Bedingungen zu checken?
Nicht immer, aber meistens ist es besser, einfach try
die Sache zu machen und catch
den Fehler zu melden, wenn es nicht klappt. Python-Entwickler nennen das EAFP, „Easier to Ask Forgiveness than Permission” (Es ist einfacher, um Vergebung zu bitten als um Erlaubnis). Das geht schneller und vermeidet bestimmte Fehler, vor allem wenn sich zwischen der Überprüfung und der Aktion was ändern könnte (z. B. wenn eine Datei gelöscht wird).
