Pythons integrierte Ausnahmen: Eine exemplarische Vorgehensweise mit Beispielen


Python verfügt über einen vollständigen Satz integrierter Ausnahmen, die eine schnelle und effiziente Möglichkeit bieten, Fehler und Ausnahmesituationen zu behandeln, die in Ihrem Code auftreten können. Für Sie als Python-Entwickler ist es von entscheidender Bedeutung, die am häufigsten verwendeten integrierten Ausnahmen zu kennen. Dieses Wissen hilft Ihnen beim Debuggen von Code, da jede Ausnahme eine spezifische Bedeutung hat, die Aufschluss über Ihren Debugging-Prozess geben kann.

Außerdem können Sie die meisten integrierten Ausnahmen in Ihrem Python-Code verarbeiten und auslösen. Dies ist eine hervorragende Möglichkeit, mit Fehlern und Ausnahmesituationen umzugehen, ohne eigene benutzerdefinierte Ausnahmen erstellen zu müssen.

In diesem Tutorial werden Sie:

  • Erfahren Sie, was Fehler und Ausnahmen in Python sind
  • Verstehen Sie, wie Python die integrierten Ausnahmen in einer Klassenhierarchie organisiert
  • Entdecken Sie die am häufigsten verwendeten integrierten Ausnahmen
  • Erfahren Sie, wie Sie in Ihrem Code integrierte Ausnahmen behandeln und auslösen

Um dieses Tutorial reibungslos durcharbeiten zu können, sollten Sie mit einigen Kernkonzepten in Python vertraut sein. Zu diesen Konzepten gehören Python-Klassen, Klassenhierarchien, Ausnahmen, tryexclusive-Blöcke und die raise-Anweisung.

Fehler und Ausnahmen in Python

Fehler und Ausnahmen sind wichtige Konzepte in der Programmierung, und Sie werden in Ihrer Programmierkarriere wahrscheinlich viel Zeit damit verbringen, sich mit ihnen zu befassen. Fehler sind konkrete Bedingungen wie Syntax- und logische Fehler, die dazu führen, dass Ihr Code nicht richtig funktioniert oder sogar abstürzt.

Häufig können Sie Fehler beheben, indem Sie den Code aktualisieren oder ändern, eine neue Version einer Abhängigkeit installieren, die Logik des Codes überprüfen usw.

Angenommen, Sie müssen sicherstellen, dass eine bestimmte Zeichenfolge eine bestimmte Anzahl von Zeichen enthält. In diesem Fall können Sie die integrierte Funktion len() verwenden:

>>> len("Pythonista") = 10
  File "<input>", line 1
    ...
SyntaxError: cannot assign to function call here.
    Maybe you meant '==' instead of '='?

In diesem Beispiel verwenden Sie den falschen Operator. Anstelle des Gleichheitsvergleichsoperators verwenden Sie den Zuweisungsoperator. Dieser Code löst einen SyntaxError aus, der einen Syntaxfehler darstellt, wie der Name schon sagt.

Um den Fehler zu beheben, müssen Sie den betroffenen Code lokalisieren und die Syntax korrigieren. Mit dieser Aktion wird der Fehler behoben:

>>> len("Pythonista") == 10
True

Jetzt funktioniert der Code ordnungsgemäß und der SyntaxError ist verschwunden. Ihr Code wird also nicht kaputt gehen und Ihr Programm wird seine normale Ausführung fortsetzen.

Aus dem obigen Beispiel kann man etwas lernen. Sie können Fehler beheben, aber Sie können sie nicht behandeln. Mit anderen Worten: Wenn Sie einen Syntaxfehler wie den im Beispiel haben, können Sie diesen Fehler nicht beheben und den Code nicht ausführen. Sie müssen die Syntax korrigieren.

Andererseits sind Ausnahmen Ereignisse, die die Ausführung eines Programms unterbrechen. Wie der Name schon sagt, treten Ausnahmen in außergewöhnlichen Situationen auf, die passieren sollten oder nicht. Um zu verhindern, dass Ihr Programm nach einer Ausnahme abstürzt, müssen Sie die Ausnahme mit dem entsprechenden Ausnahmebehandlungsmechanismus behandeln.

Um Ausnahmen besser zu verstehen, nehmen Sie an, dass Sie einen Python-Ausdruck wie a + b haben. Dieser Ausdruck funktioniert, wenn a und b beide Zeichenfolgen oder Zahlen sind:

>>> a = 4
>>> b = 3

>>> a + b
7

In diesem Beispiel funktioniert der Code korrekt, da a und b beide Zahlen sind. Der Ausdruck löst jedoch eine Ausnahme aus, wenn a und b von Typen sind, die nicht addiert werden können:

>>> a = "4"
>>> b = 3

>>> a + b
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    a + b
    ~~^~~
TypeError: can only concatenate str (not "int") to str

Da a eine Zeichenfolge und b eine Zahl ist, schlägt Ihr Code mit einer TypeError-Ausnahme fehl. Da es keine Möglichkeit gibt, Text und Zahlen hinzuzufügen, befindet sich Ihr Code in einer Ausnahmesituation.

Python verwendet Klassen zur Darstellung von Ausnahmen und Fehlern. Diese Klassen werden allgemein als Ausnahmen bezeichnet, unabhängig davon, was eine konkrete Klasse darstellt, eine Ausnahme oder einen Fehler. Ausnahmeklassen geben uns Informationen über eine Ausnahmesituation und auch Fehler, die während der Programmausführung erkannt wurden.

Das erste Beispiel in diesem Abschnitt zeigt einen Syntaxfehler in Aktion. Die Klasse SyntaxError stellt einen Fehler dar, ist jedoch als Python-Ausnahme implementiert. Das könnte verwirrend sein, aber Python verwendet Ausnahmeklassen sowohl für Fehler als auch für Ausnahmen.

Ein weiteres Beispiel für eine Ausnahme könnte sein, dass Sie an einem Code arbeiten, der eine Textdatei verarbeitet, und diese Datei nicht vorhanden ist. In diesem Fall liegt kein Fehler in Ihrem Code vor. Sie haben eine Ausnahmesituation, die Sie bewältigen müssen, um einen Programmabsturz zu verhindern. Sie haben keine Kontrolle über das Problem, da Sie durch Ändern Ihres Codes nicht sicherstellen können, dass die Datei vorhanden ist. Sie müssen die Ausnahme behandeln.

Sie können tryexclusive-Blöcke verwenden, um Ausnahmen in Python zu behandeln. Im folgenden Abschnitt lernen Sie die Grundlagen dieser Handhabung kennen.

Umgang mit Ausnahmen

Wenn Sie über einen Code verfügen, der eine Ausnahme auslöst, und Sie keinen Handler-Code für diese Ausnahme bereitstellen, wird die Ausführung Ihres Programms gestoppt. Danach erscheint auf der Standardausgabe, Ihrem Bildschirm, ein Ausnahme-Traceback.

In Python können Sie Ausnahmen mit der Anweisung tryexclusive behandeln, die es Ihnen ermöglicht, die Ausnahme abzufangen und rekuperative Aktionen bereitzustellen.

Betrachten Sie das folgende Beispiel. Eine häufige Ausnahme, die Sie sehen werden, wenn Sie beginnen, Pythons Listen und Tupel zu verwenden, ist IndexError. Diese Ausnahme tritt auf, wenn Sie versuchen, auf einen Index zuzugreifen, der außerhalb des gültigen Bereichs liegt:

>>> numbers = [1, 2, 3]
>>> numbers[5]
Traceback (most recent call last):
    ...
IndexError: list index out of range

In diesem Beispiel hat die Zahlenliste nur drei Werte. Wenn Sie also versuchen, in einem Indexierungsvorgang auf den Index 5 zuzugreifen, erhalten Sie einen IndexError, der den Code beschädigt. Sie können diesen Code in einen tryexclusive-Block einschließen, um den Ausfall zu verhindern:

>>> try:
...     numbers[5]
... except IndexError:
...     print("Your list doesn't have that index 😔")
...
Your list doesn't have that index 😔

Nun bricht der Code nicht mit einer Ausnahme ab. Stattdessen wird eine Meldung auf dem Bildschirm ausgegeben. Beachten Sie, dass der Aufruf von print() lediglich eine Platzhalteraktion für das Beispiel ist. Im realen Code können Sie hier möglicherweise andere Dinge tun.

Das obige Beispiel veranschaulicht das grundlegendste Konstrukt zur Behandlung von Ausnahmen in Python. Sie können sich das oben vorgeschlagene Tutorial ansehen, um tiefer in die Ausnahmebehandlung einzutauchen. Jetzt ist es an der Zeit, die andere Seite der Medaille kennenzulernen. Sie können in Python auch Ausnahmen auslösen.

Ausnahmen auslösen

Python hat die Anweisung raise als Teil seiner Syntax. Mit dieser Anweisung können Sie in Ihrem Code Ausnahmen als Reaktion auf Ausnahmesituationen auslösen.

Nehmen wir als Beispiel für die Verwendung der raise-Anweisung an, dass Sie eine Funktion zur Berechnung der Durchschnittsnote von Schülern schreiben müssen. Sie kommen auf die folgende Funktion:

>>> def average_grade(grades):
...     return sum(grades) / len(grades)
...

>>> average_grade([5, 4, 5, 3])
4.25

>>> average_grade([])
Traceback (most recent call last):
    ...
ZeroDivisionError: division by zero

Diese Funktion funktioniert einwandfrei. Wenn die Notenliste jedoch leer ist, erhalten Sie einen Nulldivisionsfehler, da len(grades) 0 sein wird. Wenn der Benutzer des Codes die Fehlermeldung sieht, kann es zu Verwirrung kommen. Ein Nullteilungsfehler? Was verursacht das?

Ein besserer Ansatz wäre wahrscheinlich, sicherzustellen, dass die Eingabeliste nicht leer ist, und in diesem Fall eine geeignetere Ausnahme auszulösen:

>>> def average_grade(grades):
...     if not grades:
...         raise ValueError("empty grades not allowed")
...     return sum(grades) / len(grades)
...

>>> average_grade([5, 4, 5, 3])
4.25

>>> average_grade([])
Traceback (most recent call last):
    ...
ValueError: empty grades not allowed

In dieser aktualisierten Version von average_grade() fügen Sie eine bedingte Anweisung hinzu, die prüft, ob die Eingabedaten leer sind. Wenn dies der Fall ist, lösen Sie einen ValueError mit einer expliziten Fehlermeldung aus, die klar kommuniziert, was mit dem Code nicht stimmt.

Die Ausnahmen IndexError und ValueError sind Beispiele für häufig verwendete integrierte Ausnahmen in Python. In den folgenden Abschnitten erfahren Sie mehr über diese und mehrere andere integrierte Ausnahmen.

Dieses Wissen wird Ihnen in mehrfacher Hinsicht helfen. Erstens können Sie schnell herausfinden, welche Art von Fehler möglicherweise in Ihrem Code vorliegt, was Ihre Debugging-Fähigkeiten verbessert. Zweitens verfügen Sie über ein breites Arsenal bereits verfügbarer Ausnahmen, die Sie in Ihrem eigenen Code auslösen können, sodass Sie keine benutzerdefinierten Ausnahmen erstellen müssen.

In Python integrierte Ausnahmen

Python verfügt über über sechzig integrierte Ausnahmen, die eine Vielzahl häufiger Fehler und Ausnahmesituationen darstellen. Diese Ausnahmen sind in zwei Gruppen unterteilt:

  1. Ausnahmen der Basisklasse
  2. Konkrete Ausnahmen

Die erste Gruppe von Ausnahmen umfasst Ausnahmeklassen, die hauptsächlich als Basisklassen für andere Ausnahmen dienen. In dieser Gruppe gibt es beispielsweise die Klasse Exception, die speziell dafür entwickelt wurde, Ihnen das Erstellen benutzerdefinierter Ausnahmen zu ermöglichen.

Die zweite Gruppe enthält Ausnahmen, die Sie häufig in Python-Code sehen oder bei der Ausführung von Python-Code erhalten. Beispielsweise sind Ihnen bei Ihrer täglichen Codierung wahrscheinlich einige der folgenden konkreten Ausnahmen aufgefallen:

ImportError

Erscheint, wenn eine import-Anweisung ein Modul nicht laden kann

ModuleNotFoundError

Tritt auf, wenn import ein bestimmtes Modul nicht finden kann

NameError

Wird angezeigt, wenn ein Name nicht im globalen oder lokalen Bereich definiert ist

AttributeError

Tritt auf, wenn ein Attributverweis oder eine Attributzuweisung fehlschlägt

IndexError

Tritt auf, wenn ein Indexierungsvorgang für eine Sequenz einen Index außerhalb des gültigen Bereichs verwendet

KeyError

Tritt auf, wenn ein Schlüssel in einem Wörterbuch oder einer anderen Zuordnung fehlt

ZeroDivisionError

Erscheint, wenn der zweite Operand in einer Division oder Modulo-Operation 0 ist

TypeError

Tritt auf, wenn eine Operation, Funktion oder Methode ein Objekt ungeeigneten Typs bearbeitet

ValueError

Tritt auf, wenn eine Operation, Funktion oder Methode den richtigen Argumenttyp, aber den falschen Wert empfängt

Diese Tabelle ist nur eine kleine Auswahl der in Python integrierten Ausnahmen. Eine umfassende Liste aller integrierten Ausnahmen finden Sie auf der Seite „Integrierte Ausnahmen“ der Python-Dokumentation.

Blick auf die Ausnahmehierarchie

Wie Sie bereits wissen, gibt es in Python viele integrierte Ausnahmen. Sie können sie erkunden, indem Sie den Namespace builtins in einer REPL-Sitzung untersuchen:

>>> import builtins

>>> dir(builtins)
[
    'ArithmeticError',
    'AssertionError',
    'AttributeError',
    'BaseException',
    ...
]

In diesem Beispiel importieren Sie zunächst den Namespace builtins. Anschließend verwenden Sie die integrierte Funktion dir(), um die Namen aufzulisten, die dieses Modul definiert. Beachten Sie, dass Sie die vollständige Liste der integrierten Namen erhalten. Dazwischen finden Sie die integrierten Ausnahmen.

Die in Python integrierten Ausnahmen sind als Klassen codiert und in einer Klassenhierarchie organisiert, die die folgenden Ebenen umfasst:

  • Basisklassen: Sie stellen die Basisklassen für andere Ausnahmen bereit. Sie sollten sie nur als übergeordnete Klassen verwenden. In einigen Codebasen finden Sie jedoch möglicherweise einige dieser Ausnahmen, z. B. die Klasse Exception.
  • Konkrete Ausnahmen: Dabei handelt es sich um Ausnahmen, die Python als Reaktion auf verschiedene Ausnahmesituationen auslöst. Sie bieten außerdem eine hervorragende Basis für konkrete Ausnahmen, die Sie bei Bedarf in Ihrem eigenen Code auslösen können.
  • Betriebssystemausnahmen: Sie stellen Ausnahmen bereit, die das Betriebssystem generiert. Python gibt sie an Ihre Anwendung weiter. In den meisten Fällen werden Sie diese Ausnahmen abfangen, sie aber nicht in Ihrem Code auslösen.
  • Warnungen: Sie geben Warnungen vor unerwarteten Ereignissen oder Aktionen aus, die später zu Fehlern führen können. Diese besonderen Arten von Ausnahmen stellen keine Fehler dar. Wenn Sie sie ignorieren, kann dies später zu Problemen führen, aber Sie können sie ignorieren.

Nachfolgend finden Sie ein Diagramm der Ausnahmehierarchie:

BaseException
 ├── BaseExceptionGroup
 ├── GeneratorExit
 ├── KeyboardInterrupt
 ├── SystemExit
 └── Exception
      ├── ArithmeticError
      │    ├── FloatingPointError
      │    ├── OverflowError
      │    └── ZeroDivisionError
      ├── AssertionError
      ├── AttributeError
      ├── BufferError
      ├── EOFError
      ├── ExceptionGroup [BaseExceptionGroup]
      ├── ImportError
      │    └── ModuleNotFoundError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── MemoryError
      ├── NameError
      │    └── UnboundLocalError
      ├── OSError
      │    ├── BlockingIOError
      │    ├── ChildProcessError
      │    ├── ConnectionError
      │    │    ├── BrokenPipeError
      │    │    ├── ConnectionAbortedError
      │    │    ├── ConnectionRefusedError
      │    │    └── ConnectionResetError
      │    ├── FileExistsError
      │    ├── FileNotFoundError
      │    ├── InterruptedError
      │    ├── IsADirectoryError
      │    ├── NotADirectoryError
      │    ├── PermissionError
      │    ├── ProcessLookupError
      │    └── TimeoutError
      ├── ReferenceError
      ├── RuntimeError
      │    ├── NotImplementedError
      │    └── RecursionError
      ├── StopAsyncIteration
      ├── StopIteration
      ├── SyntaxError
      │    └── IndentationError
      │         └── TabError
      ├── SystemError
      ├── TypeError
      ├── ValueError
      │    └── UnicodeError
      │         ├── UnicodeDecodeError
      │         ├── UnicodeEncodeError
      │         └── UnicodeTranslateError
      └── Warning
           ├── BytesWarning
           ├── DeprecationWarning
           ├── EncodingWarning
           ├── FutureWarning
           ├── ImportWarning
           ├── PendingDeprecationWarning
           ├── ResourceWarning
           ├── RuntimeWarning
           ├── SyntaxWarning
           ├── UnicodeWarning
           └── UserWarning

Beachten Sie, dass die meisten Klassen in der Hierarchie von Exception erben. Dies ist auch die Basisklasse, die Sie in Situationen verwenden sollten, in denen Sie eine benutzerdefinierte Ausnahme erstellen müssen.

Kennen der Basisausnahmen

In der integrierten Ausnahmehierarchie finden Sie einige Klassen, die als Basisklassen konzipiert sind. Die Klasse BaseException befindet sich oben. Dann haben Sie fünf Unterklassen:

BaseExceptionGroup

Erstellt eine Ausnahmegruppe, die alle Ausnahmen umschließt und nicht nur diejenigen, die von Exception erben

GeneratorExit

Tritt auf, wenn ein Generator oder eine Coroutine geschlossen wird

KeyboardInterrupt

Passiert, wenn der Benutzer die Interrupt-Tastenkombination drückt, die normalerweise Strg<span>+C

SystemExit

Ergibt sich aus dem Aufruf der Funktion sys.exit(), Sie können ihn aber auch direkt auslösen

Exception

Stellt eine Basisklasse für benutzerdefinierte Ausnahmen bereit, die von dieser Klasse abgeleitet werden sollten

Wie Sie sehen, haben alle diese Basisausnahmen ihren spezifischen Anwendungsfall. Es ist wichtig zu beachten, dass Sie beim Erstellen benutzerdefinierter Ausnahmen Exception und nicht BaseException verwenden sollten. Das liegt daran, dass BaseException für Ausnahmen verwendet werden sollte, die niemals im echten Code abgefangen werden sollten.

In der Praxis sollten Sie beim Abfangen und Auslösen von Ausnahmen die spezifischste Ausnahme für das vorliegende Problem verwenden.

Wenn Sie beispielsweise über einen Code verfügen, der möglicherweise einen ValueError auslösen kann, sollten Sie diese Ausnahme explizit behandeln. Wenn Sie Exception anstelle von ValueError verwenden, fängt Ihr Code Exception und alle seine Unterklassen, einschließlich ValueError, ab. Wenn Ihr Code am Ende etwas anderes als ValueError auslöst, wird dieser Fehler falsch behandelt.

Warnungen kennenlernen

Am Ende der Ausnahmehierarchie finden Sie Warnungen. Hierbei handelt es sich um bestimmte Arten von Ausnahmen, die auf etwas hinweisen, das in naher Zukunft zu Problemen führen kann. Ausnahmen sind Warnungen, die zu den Warnungskategorien gehören.

Die wahrscheinlich häufigste Warnung, die Sie beim Ausführen von Python-Code sehen, ist DeprecationWarning. Diese Warnung wird angezeigt, wenn Sie veraltete Funktionen der Sprache verwenden. Beispielsweise sind in Python 3.12 die Konstanten calendar.January und calendar.February veraltet:

>>> # Python 3.12.2
>>> calendar.January
<stdin>:1: DeprecationWarning: The 'January' attribute is deprecated,
    use 'JANUARY' instead
1

Auch wenn der Code funktioniert, weil die Konstanten noch nicht entfernt wurden, informiert Sie Python darüber, dass die Funktion veraltet ist, um zu verhindern, dass in Zukunft Probleme auftreten. Wie in der Warnmeldung angegeben, sollten Sie jetzt calendar.JANUARY verwenden.

Syntaxfehler

Die erste Ausnahme, die Sie wahrscheinlich in Python sehen werden, ist die SyntaxError-Ausnahme. Auch wenn Python für diese Art von Problemen eine Ausnahmeklasse verwendet, sollten Sie sich darüber im Klaren sein, dass es sich dabei eher um Fehler als um Ausnahmen handelt. Wie Sie bereits gelernt haben, kümmern Sie sich also nicht um die Behebung, sondern um die Behebung.

Sie werden außerdem feststellen, dass Python einige zusätzliche Ausnahmen definiert, die von SyntaxError erben:

    IndentationError
    TabError

Diese Ausnahmen sind zu erwarten, wenn Sie mit dem Erlernen von Python beginnen, und sie können Sie verwirren. Glücklicherweise verfügen moderne Code-Editoren und IDE über Funktionen, die die Bedingungen, die diese Ausnahmen generieren, erkennen und oft entfernen. In den folgenden Abschnitten erfahren Sie mehr über diese Ausnahmegruppe.

SyntaxError

Wenn Python in einem Codeabschnitt eine ungültige Syntax erkennt, löst es eine SyntaxError-Ausnahme aus. Die Ausnahme gibt einen Traceback mit hilfreichen Informationen aus, die Sie zum Debuggen des Fehlers und zum Korrigieren Ihres Codes verwenden können.

Es gibt viele Situationen, in denen ein Syntaxfehler in Ihrem Code auftreten kann. Sie können ein Komma oder eine schließende Klammer vergessen, einen Operator oder ein Schlüsselwort missbrauchen und vieles mehr.

Hier ein paar Beispiele:

>>> numbers = [1, 2, 3 4]
  File "<stdin>", line 1
    numbers = [1, 2, 3 4]
                     ^^^
SyntaxError: invalid syntax. Perhaps you forgot a comma?

>>> 7 = 7
  File "<stdin>", line 1
    7 = 7
    ^
SyntaxError: cannot assign to literal here.
    Maybe you meant '==' instead of '='?

>>> class = "Economy"
  File "<stdin>", line 1
    class = "Economy"
          ^
SyntaxError: invalid syntax

Dies sind häufige Syntaxfehler, auf die Sie manchmal stoßen können. Die gute Nachricht ist, dass Sie mit den verbesserten Fehlermeldungen, die Python heutzutage bereitstellt, den Fehler schnell aufspüren und beheben können.

IndentationError

Im Gegensatz zu anderen Programmiersprachen ist die Einrückung Teil der Python-Syntax. Um einen Codeblock in Python abzugrenzen, verwenden Sie Einrückungen. Daher erhalten Sie möglicherweise eine Fehlermeldung, wenn die Einrückung nicht korrekt ist. Python verwendet die Ausnahme IndentationError, um dieses Problem zu kennzeichnen.

Diese Ausnahme kann auftreten, wenn Sie mit dem Erlernen von Python beginnen. Es kann auch auftreten, wenn Sie Code an komplizierten Stellen kopieren und einfügen. Glücklicherweise tritt dieser Fehler heutzutage nicht mehr häufig auf, da moderne Code-Editoren Codeeinrückungen automatisch korrigieren können.

Um die Ausnahme in Aktion zu sehen, betrachten Sie das folgende Beispiel einer Funktion, deren Codeblock eine ungleichmäßige Einrückung verwendet:

>>> def greet(name):
...     print(f"Hello, {name}!")
...   print("Welcome to Real Python!")
  File "<stdin>", line 3
    print("Welcome to Real Python!")
                                   ^
IndentationError: unindent does not match any outer indentation level

In diesem Beispiel haben die hervorgehobenen Zeilen unterschiedliche Einzüge. Die erste Zeile wird um vier Leerzeichen eingerückt, während die zweite Zeile um zwei Leerzeichen eingerückt wird. Diese Nichtübereinstimmung der Einrückung löst einen IndentationError aus. Auch hier gilt: Da es sich hierbei um einen Syntaxfehler handelt, meldet Python ihn sofort. Sie können das Problem schnell beheben, indem Sie die Einrückung korrigieren.

TabError

Ein weiteres mögliches Problem für diejenigen, die aus anderen Programmiersprachen kommen, ist die Vermischung von Tabulator- und Leerzeichen beim Einrücken von Python-Code. Die Ausnahme für dieses Problem ist TabError, eine Unterklasse von IndentationError. Es handelt sich also um eine weitere Syntaxfehlerausnahme.

Hier ist ein Beispiel, bei dem Python eine TabError-Ausnahme auslöst:

def greet(name):
    print(f"Hello, {name}!")
        print("Welcome to Real Python!")

In diesem Beispiel wird die erste Zeile in greet() mit einem Tabulatorzeichen eingerückt, während die zweite Zeile mit acht Leerzeichen eingerückt wird, was der üblichen Anzahl von Leerzeichen entspricht, die ein Tabulatorzeichen ersetzt.

Um das Beispiel auszuprobieren, führen Sie die Datei über die Befehlszeile aus:

$ python greeting.py
  File ".../greeting.py", line 3
    print("Welcome to Real Python!")
TabError: inconsistent use of tabs and spaces in indentation

Da bei der Codeeinrückung Tabulatoren und Leerzeichen gemischt werden, erhalten Sie einen TabError-Einrückungsfehler. Auch hier sind TabError-Ausnahmen heutzutage nicht mehr üblich, da moderne Code-Editoren sie automatisch beheben können. Wenn Ihr Editor also gut auf die Python-Entwicklung eingestellt ist, werden Sie diese Ausnahme wahrscheinlich nicht in Aktion sehen.

Importbezogene Ausnahmen

Beim Importieren von Paketen, Modulen und deren Inhalten schlägt Ihr Code manchmal mit der Fehlermeldung fehl, dass die Zieldatei nicht gefunden wurde. In der Praxis kann es zu einer von zwei importbezogenen Ausnahmen kommen:

    ModuleNotFoundError
    ImportError

Beachten Sie, dass die Ausnahme ModuleNotFoundError eine Unterklasse von ImportError mit einer spezifischeren Bedeutung oder einem spezifischeren Ziel ist, wie Sie gleich erfahren werden.

In den folgenden Abschnitten erfahren Sie mehr über diese beiden Ausnahmen und wann Python sie auslöst. Dieses Wissen wird Ihnen helfen, das Problem zu beheben und Ihren Code zum Laufen zu bringen.

ModuleNotFoundError

Wie Sie bereits erfahren haben, ist die Ausnahme ModuleNotFoundError eine Unterklasse von ImportError mit einem spezifischeren Ziel. Python löst diese Ausnahme aus, wenn es das Modul, aus dem Sie etwas importieren möchten, nicht finden kann:

>>> import non_existing
Traceback (most recent call last):
    ...
ModuleNotFoundError: No module named 'non_existing'

Wenn Python das Zielmodul nicht in seinem Importsuchpfad findet, löst es eine ModuleNotFoundError-Ausnahme aus. Um dieses Problem zu beheben, müssen Sie sicherstellen, dass Ihr Modul in sys.path aufgeführt ist.

Da ModuleNotFoundError eine Unterklasse von ImportError ist, können Sie, wenn Sie Letzteres explizit in einem tryexclusive-Block verwenden Ich werde beide Ausnahmen abfangen. Wenn Sie also Situationen abfangen möchten, in denen das Zielmodul nicht vorhanden ist, sollten Sie konkret sein und ModuleNotFoundError verwenden.

ImportError

Python löst die ImportError-Ausnahme für alle importbezogenen Probleme aus, die nicht von ModuleNotFoundError abgedeckt werden. Dies kann aus zwei Hauptgründen passieren:

  1. Eine import module-Anweisung schlägt aus einem Grund fehl, ein Modul zu laden, der nicht durch ModuleNotFoundError abgedeckt wird.
  2. Eine from module import name-Anweisung kann name nicht im Zielmodul finden.

Fahren Sie nun fort und führen Sie die folgende import-Anweisung aus, um die ImportError-Ausnahme in Aktion zu sehen:

>>> from sys import non_existing
Traceback (most recent call last):
    ...
ImportError: cannot import name 'non_existing' from 'sys' (unknown location)

In diesem Beispiel versuchen Sie, den Namen non_existing aus dem Modul sys zu importieren. Da der Name in diesem Modul nicht vorhanden ist, erhalten Sie einen ImportError. Sie können das Problem schnell beheben, indem Sie den richtigen Zielnamen angeben.

Im realen Code können Sie ImportError oder ModuleNotFoundError nutzen, um je nach Verfügbarkeit der Bibliothek optional verschiedene Module oder Bibliotheken zu laden, die eine bestimmte Funktionalität bereitstellen.

Angenommen, Sie müssen eine TOML-Datei analysieren und ihren Inhalt lesen. In diesem Fall können Sie das Standardbibliotheksmodul tomllib verwenden, wenn Sie Python 3.11 oder höher verwenden. Andernfalls sollten Sie die Drittanbieterbibliothek tomli verwenden, die mit tomllib kompatibel ist.

So können Sie das machen:

try:
    import tomllib  # Python >= 3.11
except ModuleNotFoundError:
    import tomli as tomllib  # Python < 3.11

Der Import in der try-Klausel zielt auf das Standardbibliotheksmodul tomllib ab. Wenn dieser Import eine Ausnahme auslöst, weil Sie eine Python-Version vor 3.11 verwenden, importiert die exclusive-Klausel die Drittanbieterbibliothek tomli, die Sie als installieren müssen eine externe Abhängigkeit Ihres Projekts.

Ausnahmen für Suchfehler

Das Erhalten eines IndexError beim Durchführen von Indizierungsvorgängen für eine Sequenz oder eines KeyError beim Nachschlagen von Schlüsseln in Wörterbüchern ist ebenfalls ein häufiges Problem in Python. In den folgenden Abschnitten erfahren Sie mehr über diese beiden Ausnahmen und wann sie in Ihrem Code auftreten können.

IndexError

Die IndexError-Ausnahme tritt auf, wenn Sie versuchen, einen Wert aus einer Sequenz mithilfe eines Index außerhalb des gültigen Bereichs abzurufen:

>>> colors = [
...     "red",
...     "orange",
...     "yellow",
...     "green",
...     "blue",
...     "indigo",
...     "violet",
... ]

>>> colors[10]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    colors[10]
    ~~~~~~^^^^
IndexError: list index out of range

In diesem Beispiel verwenden Sie 10 als Index, um einen Wert aus Ihrer Farben-Liste abzurufen. Da die Liste nur sieben Elemente enthält, reichen die gültigen Indizes von 0 bis 6. Ihr Zielindex liegt außerhalb des gültigen Bereichs und Python gibt eine IndexError-Ausnahme aus.

IndexError kann in Python eine häufige Ausnahme sein, insbesondere wenn Sie dynamisch generierte Indizes verwenden. Um das Problem zu beheben, müssen Sie herausfinden, welchen Index Ihr Code verwendet, um einen Wert aus der Zielsequenz abzurufen, und dann den Indexbereich anpassen, um das Problem zu beheben.

Wenn Sie den Bereich der Indizes nicht steuern können, können Sie die Ausnahme in einem tryexclusive-Block abfangen und die entsprechenden Wiederherstellungsmaßnahmen ergreifen.

Sie können die Ausnahme IndexError auch in Ihrem eigenen Code auslösen. Diese Ausnahme kann sinnvoll sein, wenn Sie benutzerdefinierte sequenzartige Datenstrukturen erstellen. Angenommen, Sie müssen einen sequenzähnlichen Stapel erstellen:

class Stack:
    def __init__(self, items=None):
        self.items = list(items) if items is not None else []

    def push(self, item):
        self.items.append(item)

    def pop(self):
        return self.items.pop()

    def __len__(self):
        return len(self.items)

    def __getitem__(self, index):
        try:
            return self.items[index]
        except IndexError:
            raise IndexError(
                f"your stack only has {len(self)} items!"
            ) from None

In diesem Beispiel definieren Sie Stack und stellen die Methoden .push() und .pop() bereit. Die erstere Methode hängt ein neues Element oben an den Stapel an, während die letztere das Element oben am Stapel entfernt und zurückgibt.

Dann haben Sie die spezielle Methode .__len__() zur Unterstützung der integrierten Funktion len(), die Ihnen die Anzahl der Elemente im Stapel liefert.

Schließlich haben Sie die Methode .__getitem__(). Diese spezielle Methode verwendet einen Index als Argument und gibt das Element am Eingabeindex zurück. Der Block tryexclusive fängt die Ausnahme IndexError ab und löst sie mit einer spezifischeren Fehlermeldung erneut aus. Sie verlassen sich nicht auf die ursprüngliche Nachricht, wodurch Ihr Code fokussierter wird.

KeyError

Wenn Sie versuchen, einen nicht vorhandenen Schlüssel aus einem Wörterbuch abzurufen, erhalten Sie ebenfalls eine KeyError-Ausnahme. Dieses Problem tritt auch in Python häufig auf:

>>> fruits = {"apple": 0.40, "orange": 0.35, "banana": 0.25}

>>> fruits["grape"]
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    fruits["grape"]
    ~~~~~~^^^^^^^^^
KeyError: 'grape'

In diesem Beispiel versuchen Sie, den Schlüssel grape aus dem Wörterbuch fruits abzurufen und erhalten eine KeyError-Ausnahme. In diesem Fall ist die Fehlermeldung ziemlich kurz. Es wird nur der Name des fehlenden Schlüssels angezeigt.

Auch hier kann die Verwendung dynamisch generierter Schlüssel die Ursache des Problems sein. Um das Problem zu beheben, müssen Sie also die generierten und vorhandenen Schlüssel in Ihrem Code überprüfen. Alternativ können Sie die Methode .get() mit einem entsprechenden Standardwert verwenden, wenn dies eine geeignete Lösung für Ihren Anwendungsfall ist.

Schließlich können Sie auch einen KeyError in Ihrem Code auslösen. Dies kann hilfreich sein, wenn Sie eine wörterbuchähnliche Klasse erstellen und Ihren Benutzern eine aussagekräftigere Fehlermeldung bereitstellen müssen.

Namensfehler: NameError

Die NameError-Ausnahme kommt auch recht häufig vor, wenn Sie mit Python beginnen. Diese Ausnahme tritt auf, wenn Sie versuchen, einen Namen zu verwenden, der in Ihrem aktuellen Namespace nicht vorhanden ist. Diese Ausnahme hängt also eng mit Bereichen und Namespaces zusammen.

Angenommen, Sie arbeiten in einer REPL-Sitzung. Sie haben das Modul sys importiert, um es in Ihrer aktuellen Aufgabe zu verwenden. Aus irgendeinem Grund starten Sie die interaktive Sitzung neu und versuchen, sys zu verwenden, ohne es erneut zu importieren:

>>> sys.path
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    sys.path
    ^^^
NameError: name 'sys' is not defined. Did you forget to import 'sys'?

Da Sie die interaktive Sitzung neu gestartet haben, sind alle Namen und Module, die Sie zuvor importiert haben, verschwunden. Wenn Sie nun versuchen, das Modul sys zu verwenden, erhalten Sie einen NameError.

Beachten Sie, dass kein NameError angezeigt wird, wenn der unbekannte Name in einem qualifizierten Namen hinter dem Punkt steht. In diesem Fall erhalten Sie stattdessen eine AttributeError-Ausnahme, über die Sie im folgenden Abschnitt mehr erfahren.

Objektbezogene Ausnahmen

Bei der Arbeit mit Python-Klassen, -Objekten und integrierten Typen können einige Ausnahmen auftreten. Die häufigsten sind die folgenden:

    TypeError
    ValueError
    AttributeError

In den folgenden Abschnitten erfahren Sie, wann diese Ausnahmen auftreten und wie Sie in Ihrem Python-Code damit umgehen.

TypeError

Python löst eine TypeError-Ausnahme aus, wenn Sie eine Operation oder Funktion auf ein Objekt anwenden, das diese Operation nicht unterstützt. Erwägen Sie beispielsweise den Aufruf der integrierten Funktion len() mit einer Zahl als Argument:

>>> len(42)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    len(42)
TypeError: object of type 'int' has no len()

In diesem Beispiel ist das Argument für len() eine Ganzzahl, die die Funktion nicht unterstützt. Daher erhalten Sie eine Fehlermeldung mit einer entsprechenden Meldung.

In der Praxis können Sie die Ausnahme TypeError in Ihrem eigenen Code abfangen, wenn Sie ein typbezogenes Problem verhindern müssen. Sie können die Ausnahme auch in Ihrem Code auslösen, um auf ein typbezogenes Problem hinzuweisen. Angenommen, Sie möchten eine Funktion schreiben, die eine Iterable von Zahlen annimmt und eine Liste quadrierter Werte zurückgibt. Sie möchten sicherstellen, dass die Funktion nur iterierbare Objekte akzeptiert.

In dieser Situation können Sie eine Funktion wie die folgende haben:

>>> def squared(numbers):
...     try:
...         iter(numbers)
...     except TypeError:
...         raise TypeError(
...             f"expected an iterable, got '{type(numbers).__name__}'"
...         ) from None
...     return [number**2 for number in numbers]
...

>>> squared([1, 2, 3, 4, 5])
[1, 4, 9, 16, 25]

>>> squared(42)
Traceback (most recent call last):
    ...
TypeError: expected an iterable, got 'int'

In diesem Beispiel verwendet Ihre Funktion die integrierte Funktion iter(), um die Eingabedaten zu überprüfen. Diese Funktion löst eine TypeError-Ausnahme aus, wenn die bereitgestellte Eingabe nicht iterierbar ist. Sie fangen diese Ausnahme ab und lösen sie erneut aus, jedoch mit einer benutzerdefinierten Fehlermeldung, die dem Zweck Ihres Codes entspricht. Anschließend erstellen Sie die Liste der quadrierten Werte mithilfe eines Listenverständnisses.

ValueError

In ähnlicher Weise löst Python die Ausnahme ValueError aus, wenn eine Operation oder Funktion ein Argument erhält, das den richtigen Typ, aber einen ungeeigneten Wert hat:

>>> float("1")
1.0

>>> float("one")
Traceback (most recent call last):
    ...
ValueError: could not convert string to float: 'one'

In diesem Beispiel verwenden Sie zunächst die integrierte Funktion float(), um eine Zeichenfolge in eine Gleitkommazahl umzuwandeln. Die Eingabezeichenfolge enthält einen numerischen Wert, sodass der Vorgang erfolgreich ist.

Im zweiten Beispiel rufen Sie dieselbe Funktion mit einer Zeichenfolge auf, die keine gültige Zahl darstellt, und erhalten eine ValueError-Ausnahme. Beachten Sie, dass das Eingabeargument eine Zeichenfolge ist, was dem richtigen Argumenttyp entspricht. Allerdings ist die Eingabezeichenfolge kein gültiger numerischer Wert, Sie haben also den richtigen Typ, aber den falschen Wert.

Sie können auch ValueError in Ihrem Python-Code verwenden. Diese Ausnahme kann in verschiedenen Situationen angebracht sein. Angenommen, Sie müssen eine Klasse schreiben, um Regenbogenfarben darzustellen. Diese Klasse verfügt über sieben zulässige Farbnamen, die Sie mit Zeichenfolgen darstellen können:

COLORS = {
    "Red": {"Hex": "#FF0000", "RGB": (255, 0, 0)},
    "Orange": {"Hex": "#FF7F00", "RGB": (255, 127, 0)},
    "Yellow": {"Hex": "#FFFF00", "RGB": (255, 255, 0)},
    "Green": {"Hex": "#00FF00", "RGB": (0, 255, 0)},
    "Blue": {"Hex": "#0000FF", "RGB": (0, 0, 255)},
    "Indigo": {"Hex": "#4B0082", "RGB": (75, 0, 130)},
    "Violet": {"Hex": "#8B00FF", "RGB": (139, 0, 255)},
}

class RainbowColor:
    def __init__(self, name="Red"):
        name = name.title()
        if name not in COLORS:
            raise ValueError(f"{name} is not a valid rainbow color")
        self.name = name

    def as_hex(self):
        return COLORS[self.name]["Hex"]

    def as_rgb(self):
        return COLORS[self.name]["RGB"]

In diesem Beispiel definieren Sie zunächst eine COLORS-Konstante, die die Regenbogenfarben und ihre entsprechende Hex- und RGB-Darstellung enthält.

Anschließend definieren Sie die Klasse RainbowColor. Im Klasseninitialisierer verwenden Sie eine Bedingung, um sicherzustellen, dass der Name der Eingabefarbe eine der Regenbogenfarben ist. Wenn das nicht der Fall ist, lösen Sie einen ValueError aus, weil der Farbname vom richtigen Typ ist, aber den falschen Wert hat. Es ist eine Zeichenfolge, aber kein gültiger Farbname.

So funktioniert der Kurs in der Praxis:

>>> from rainbow import RainbowColor

>>> color = RainbowColor("Gray")
Traceback (most recent call last):
    ...
ValueError: Gray is not a valid rainbow color

>>> color = RainbowColor("Blue")
>>> color.name
'Blue'
>>> color.as_rgb()
(0, 0, 255)

Wenn Sie in diesem Codeausschnitt versuchen, einen nicht zulässigen Farbnamen zu übergeben, erhalten Sie einen ValueError. Wenn der Farbname gültig ist, funktioniert die Klasse einwandfrei.

AttributeError

Eine weitere häufige Ausnahme, die Sie bei der Arbeit mit Python-Klassen sehen werden, ist AttributeError. Diese Ausnahme tritt auf, wenn das angegebene Objekt das Attribut oder die Methode, auf die Sie zugreifen möchten, nicht definiert.

Nehmen Sie zum Beispiel Ihre RainbowClass aus dem vorherigen Abschnitt. Diese Klasse verfügt über ein Attribut und zwei Methoden: .name, .as_hex() und .as_rgb(). Wenn Sie darauf zugreifen, erhalten Sie ein Ergebnis entsprechend ihrer Tätigkeit. Angenommen, Sie versuchen, auf eine Methode namens .as_hsl() zuzugreifen. Was würde passieren?

Hier ist die Antwort:

>>> from rainbow import RainbowColor

>>> color = RainbowColor("Blue")

>>> color.as_hsl()
Traceback (most recent call last):
    ...
AttributeError: 'RainbowColor' object has no attribute 'as_hsl'

Da RainbowColor die Methode .as_hsl() nicht definiert, erhalten Sie einen AttributeError, der Ihnen mitteilt, dass die Klasse kein Attribut hat passt zu diesem Namen.

Dieser Fehler kann in komplexen Klassenhierarchien häufig auftreten, die ähnliche Klassen mit leicht unterschiedlichen Schnittstellen definieren. In dieser Situation denken Sie vielleicht, dass eine bestimmte Klasse eine bestimmte Methode oder ein bestimmtes Attribut definiert, aber das ist möglicherweise nicht der Fall. Um das Problem zu beheben, können Sie einen Blick auf die Klassendefinition oder -dokumentation werfen, um sicherzustellen, dass Sie nur die Attribute und Methoden verwenden, die die Klasse definiert.

Sie können die Ausnahme AttributeError überspringen, indem Sie die integrierte Funktion hasattr() verwenden:

>>> if hasattr(color, "as_hsl"):
...     color.as_hsl()
... else:
...     print("Hmm, you can't call that.")
...
Hmm, you can't call that.

In diesem Beispiel verwenden Sie hasattr(), um explizit zu prüfen, ob das color-Objekt ein Attribut namens "as_hsl" hat.

Sie können die Ausnahme AttributeError auch in Ihren benutzerdefinierten Klassen abfangen und auslösen. In der Praxis kann diese Ausnahme sehr nützlich sein, da Python Sie dazu ermutigt, einen Codierungsstil zu verwenden, der auf der Behandlung von Ausnahmen namens EAFP basiert (es ist einfacher, um Verzeihung als um Erlaubnis zu bitten).

Kurz gesagt bedeutet die Verwendung dieses Stils, dass Sie entscheiden, Fehler und Ausnahmen zu behandeln, wenn sie auftreten. Im Gegensatz dazu versuchen Sie beim LBYL-Stil (Look before you leap), Fehler und Ausnahmen zu verhindern, bevor sie auftreten. Das haben Sie im obigen Beispiel getan.

Anstatt sich also auf hasattr() zu verlassen, sollten Sie das obige Beispiel wie folgt schreiben:

>>> try:
...     color.as_hsl()
... except AttributeError:
...     print("Hmm, you can't call that.")
...
Hmm, you can't call that.

Dieser Codierungsstil ist direkter. Sie gehen und rufen die gewünschte Methode auf. Wenn dies mit einem AttributeError fehlschlägt, führen Sie alternative Aktionen aus.

Schließlich erhalten Sie auch eine AttributeError-Ausnahme, wenn Sie versuchen, auf ein Objekt zuzugreifen, das nicht in einem bereits importierten Modul definiert ist:

>>> import sys

>>> sys.non_existing
Traceback (most recent call last):
    ...
AttributeError: module 'sys' has no attribute 'non_existing'

Beachten Sie, dass in diesem Beispiel kein Importfehler angezeigt wird. Stattdessen erhalten Sie eine AttributeError-Ausnahme. Das liegt daran, dass die in einem Modul definierten Objekte zu Attributen dieses Moduls werden.

Ausnahmen bei arithmetischen Fehlern

Die Ausnahmeklasse ArithmeticError ist die Basisklasse für integrierte Ausnahmen, die sich auf drei verschiedene Arten von Rechenfehlern beziehen:

    ZeroDivisionError
    FloatingPointError
    OverflowError

Die häufigste dieser drei Ausnahmen ist ZeroDivisionError. Der FloatingPointError ist als integrierte Ausnahme definiert, wird aber heutzutage von Python nicht mehr verwendet. In den folgenden Abschnitten erfahren Sie, wann die Ausnahmen ZeroDivisionError und OverflowError in Ihrem Code auftreten können.

ZeroDivisionError

Python löst die Ausnahme ZeroDivisionError aus, wenn der Divisor oder rechte Operand einer Division Null ist. Nehmen wir als kurzes Beispiel an, dass Sie eine Funktion schreiben müssen, um die Durchschnittsnote einer Gruppe von Schülern zu berechnen. In diesem Fall können Sie sich die folgende Funktion ausdenken:

>>> def average_grade(grades):
...     return sum(grades) / len(grades)
...

>>> average_grade([4, 3, 3, 4, 5])
3.8

Diese Funktion funktioniert einwandfrei, wenn Sie geeignete Eingabedaten verwenden. Aber was würde passieren, wenn Sie die Funktion mit einem leeren Listenobjekt aufrufen würden? Hier ist die Antwort:

>>> average_grade([])
Traceback (most recent call last):
    ...
ZeroDivisionError: division by zero

Da die Eingabeliste leer ist, gibt die Funktion len() 0 zurück. Dieser Rückgabewert erzeugt eine ZeroDivisionError-Ausnahme, wenn die tatsächliche Division erfolgt.

Um das Problem zu beheben, können Sie die Ausnahme abfangen und dem Benutzer eine beschreibende Fehlermeldung anzeigen:

>>> def average_grade(grades):
...     try:
...         return sum(grades) / len(grades)
...     except ZeroDivisionError:
...         raise ValueError(
...             "you should pass at least one grade to average_grade()"
...         ) from None
...

>>> average_grade([])
Traceback (most recent call last):
    ...
ValueError: you should pass at least one grade to average_grade()

In dieser aktualisierten Version von average_grade() fangen Sie den ZeroDivisionError ab, den eine leere Eingabeliste generiert, und lösen einen ValueError mit einem benutzerfreundlichen Fehler aus Nachricht.

Schließlich tritt die ZeroDivisionError-Ausnahme auch auf, wenn der rechte Operand einer Modulo-Operation Null ist:

>>> 42 % 0
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    42 % 0
    ~~~^~~
ZeroDivisionError: integer modulo by zero

Der Modulo-Operator gibt den Rest einer Division zweier Zahlen zurück. Da die Division der Zahlen der erste Schritt zur Berechnung des Restes ist, können Sie einen ZeroDivisionError erhalten, wenn der rechte Operand 0 ist.

OverflowError

Der OverflowError kommt nicht so häufig vor. Python löst diese Ausnahme aus, wenn das Ergebnis einer arithmetischen Operation zu groß ist und es keine Möglichkeit gibt, es darzustellen:

>>> 10.0**1000
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    10.0**1000
    ~~~~^^~~~~
OverflowError: (34, 'Result too large')

In diesem Beispiel ist die Zahl, die sich aus der Power-Operation ergibt, zu hoch und Python kann sie nicht korrekt darstellen. Sie erhalten also eine OverflowError-Ausnahme.

Iterationsbezogene Ausnahmen

Python verfügt über einige integrierte Ausnahmen, die eng mit der Iteration zusammenhängen. Der RecursionError bezieht sich auf rekursiven Code und kann als Standardausnahme bezeichnet werden. Dann gibt es die Ausnahme StopIteration, die Python intern verwendet, um den Ausführungsfluss von for-Schleifen zu steuern. Diese Ausnahme hat ein asynchrones Gegenstück namens AsyncStopIteration, das Python in async for-Schleifen verwendet.

In den folgenden Abschnitten erfahren Sie mehr über die Ausnahmen RecursionError und StopIteration und wie Python sie verwendet.

RecursionError

Eine Funktion, die sich selbst aufruft, wird als rekursive Funktion bezeichnet. Diese Art von Funktionen bilden die Grundlage einer Iterationstechnik namens Rekursion.

Betrachten Sie die folgende Spielzeugfunktion als Beispiel für eine rekursive Funktion:

>>> def recurse():
...     recurse()
...

Diese Funktion folgt nicht den Rekursionsregeln, da sie keinen Basisfall hat, der die Wiederholung stoppt. Es gibt nur einen rekursiven Fall. Wenn Sie also die Funktion aufrufen, erhalten Sie eine RecursionError-Ausnahme:

>>> recurse()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    recurse()
  File "<input>", line 2, in recurse
    recurse()
  File "<input>", line 2, in recurse
    recurse()
  File "<input>", line 2, in recurse
    recurse()
  [Previous line repeated 981 more times]
RecursionError: maximum recursion depth exceeded

Python löst eine RecursionError-Ausnahme aus, wenn der Interpreter erkennt, dass die maximale Rekursionstiefe überschritten wird. Dies kann passieren, wenn Ihr Basisfall nicht ordnungsgemäß funktioniert oder wenn die erforderliche Anzahl von Rekursionen zur Durchführung der Berechnung das Rekursionslimit überschreitet.

Sie können die Funktion sys.getrecursionlimit() verwenden, um Ihre aktuelle Rekursionstiefe zu überprüfen:

>>> import sys

>>> sys.getrecursionlimit()
1000

Das Ergebnis des Aufrufs dieser Funktion ist eine Zahl, die angibt, wie oft sich eine rekursive Funktion in Python selbst aufrufen kann. Wenn es für Ihren Anwendungsfall angemessen ist, können Sie mit der Funktion sys.setrecursionlimit() auch ein anderes Rekursionslimit festlegen.

StopIteration

Python löst eine StopIteration-Ausnahme aus, wenn Sie die integrierte Funktion next() für einen erschöpften Iterator aufrufen. Sein Zweck besteht darin, zu signalisieren, dass sich keine weiteren Elemente im Iterator befinden. Daher verwendet Python diese Ausnahme intern, um die Iteration zu steuern.

Betrachten Sie das folgende Spielzeugbeispiel:

>>> numbers_iterator = iter([1, 2, 3])

>>> next(numbers_iterator)
1
>>> next(numbers_iterator)
2
>>> next(numbers_iterator)
3
>>> next(numbers_iterator)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    next(numbers_iterator)
StopIteration

In diesem Beispiel verwenden Sie die integrierte Funktion iter(), um einen Iterator aus einer kurzen Liste von Zahlen zu erstellen. Anschließend rufen Sie wiederholt next() auf, um den Iterator zu nutzen. Der vierte Aufruf dieser Funktion löst eine StopIteration-Ausnahme aus, um zu signalisieren, dass der Iterator keine weiteren Elemente zum Abrufen hat.

Intern verwendet Python diese Ausnahme, um for-Schleifen zu beenden. Mit anderen Worten: Wenn eine for-Schleife über einen Iterator iteriert, stoppt die Schleife, wenn sie die Ausnahme StopIteration erhält. Aus diesem Grund ist es nicht üblich, diese Ausnahme in Aktion zu sehen. Beachten Sie, dass die for-Schleife von Python unter der Haube next() aufruft, um die Iteration durchzuführen.

In der Praxis können Sie die Ausnahme StopIteration in Ihrem Code als Teil einer Implementierung des Iteratorprotokolls verwenden. Dieses Protokoll besteht aus zwei speziellen Methoden:

  1. .__iter__() wird aufgerufen, um den Iterator zu initialisieren. Es muss ein Iteratorobjekt zurückgeben.
  2. .__next__() wird aufgerufen, um den Iterator zu durchlaufen. Es muss den nächsten Wert im Datenstrom zurückgeben.

Wenn Sie diese Methoden in einer benutzerdefinierten Klasse bereitstellen, unterstützt Ihre Klasse die Iteration. Um zu signalisieren, wann die Iteration beendet werden muss, müssen Sie die Ausnahme StopIteration in der Methode .__next__() auslösen.

Um die Verwendung von StopIteration zu veranschaulichen, nehmen wir an, dass Sie eine benutzerdefinierte Klasse erstellen müssen, die eine Liste von Werten übernimmt und einen Iterator über deren Quadrate erstellt:

class SquareIterator:
    def __init__(self, values):
        self.values = values
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.values):
            raise StopIteration
        square = self.values[self.index] ** 2
        self.index += 1
        return square

In dieser Klasse verwendet der Initialisierer eine Liste von Werten als Argument. Außerdem wird ein Referenzindex definiert, der bei 0 beginnt. Die Methode .__iter__() gibt self zurück, was üblich ist, wenn Sie das Iterator-Protokoll wie in diesem Beispiel verwenden.

In der Methode .__next__() prüfen Sie, ob der aktuelle Index größer oder gleich der Anzahl der Werte in der Eingabeliste ist. Wenn dies der Fall ist, lösen Sie eine StopIteration aus, um zu signalisieren, dass der Iterator erschöpft ist. Als nächstes berechnen Sie das Quadrat des aktuellen Werts und geben es als Ergebnis der Methode zurück.

Jetzt können Sie Instanzen dieser Klasse in einer for-Schleife verwenden:

>>> from squares import SquareIterator

>>> for value in SquareIterator([1, 2, 3]):
...     print(value)
...
1
4
9

Ihr Iterator funktioniert gut. Es generiert quadratische Werte und unterstützt die Iteration. Beachten Sie, dass die Ausnahme StopIteration nicht auftritt. Allerdings verwendet Python die Ausnahme intern, um die Schleife zu beenden, wenn der Iterator fertig ist.

Dateibezogene Ausnahmen

Bei der Verarbeitung von Dateien in Ihrem Python-Code können verschiedene Probleme auftreten. Ihr Code versucht möglicherweise, eine bereits vorhandene Datei zu erstellen, auf eine nicht vorhandene Datei zuzugreifen, einen Dateivorgang für ein Verzeichnis statt für eine Datei auszuführen oder es treten Berechtigungsprobleme auf. Python verfügt über dateibezogene Ausnahmen, die diese Situationen kennzeichnen.

Hier sind einige der beliebtesten:

    FileExistsError
    FileNotFoundError
    PermissionError

In den folgenden Abschnitten erfahren Sie mehr über diese integrierten Ausnahmen und wann sie in Python auftreten.

FileExistsError

Wenn Sie versuchen, eine bereits vorhandene Datei oder ein Verzeichnis zu erstellen, löst Python die integrierte Ausnahme FileExistsError aus.

Um diese Ausnahme in Aktion zu sehen, müssen Sie beispielsweise eine Datei in Ihrem Arbeitsverzeichnis erstellen und Text hineinschreiben. Sie möchten jedoch vermeiden, die Datei zu ersetzen, wenn sie bereits vorhanden ist. In diesem Fall können Sie den FileExistsError nutzen und den folgenden Code schreiben:

try:
    with open("hello.txt", mode="x") as file:
        file.write("Hello, World!")
except FileExistsError:
    print("The file already exists")

In diesem Beispiel verwenden Sie die integrierte Funktion open(), um eine Datei namens hello.txt zu öffnen. Der "x"-Modus bedeutet, dass Sie die Datei zur exklusiven Erstellung öffnen möchten, was fehlschlägt, wenn die Datei bereits vorhanden ist.

Fahren Sie nun fort und führen Sie diese hello.py-Datei über Ihre Befehlszeile aus:

$ python hello.py

Dieser Befehl gibt keine Ausgabe aus. Wenn Sie sich jedoch Ihr Arbeitsverzeichnis ansehen, sehen Sie eine neue Datei namens hello.txt mit dem Text "Hello, World!" darin.

Wenn Sie den Befehl erneut ausführen, ist das Ergebnis anders:

$ python hello.py
The file already exists

Da die Datei hello.txt dieses Mal bereits vorhanden ist, löst der Dateierstellungscode eine FileExistsError-Ausnahme aus und die exclusive-Klausel gibt einen Fehler aus Meldung auf dem Bildschirm.

FileNotFoundError

Python löst die Ausnahme FileNotFoundError aus, wenn eine Datei oder ein Verzeichnis angefordert wird, aber am Zielspeicherort nicht vorhanden ist. Angenommen, Sie haben versehentlich die Datei hello.txt entfernt, die Sie im vorherigen Abschnitt erstellt haben. Wenn Sie versuchen, den Inhalt der Datei zu lesen, erhalten Sie eine Fehlermeldung:

>>> with open("hello.txt", mode="r") as file:
...     print(file.read())
...
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    with open("hello.txt", mode="r") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'hello.txt'

In diesem Codeausschnitt versuchen Sie, die Datei hello.txt zu öffnen, um ihren Inhalt zu lesen. Da Sie die Datei vor diesem Vorgang entfernt haben, schlägt Ihr Code mit der Ausnahme FileNotFoundError fehl.

Um dieses Problem zu lösen, können Sie Ihren Code wie im folgenden Beispiel umschreiben:

>>> try:
...     with open("hello.txt", mode="r") as file:
...         print(file.read())
... except FileNotFoundError:
...     print("The file doesn't exist")
...
The file doesn't exist

Jetzt verwenden Sie einen tryexclusive-Block, um die FileNotFoundError-Ausnahme zu behandeln und zu verhindern, dass Ihr Code ausbricht.

PermissionError

Ein weiteres häufiges Problem bei der Verarbeitung von Dateien besteht darin, dass Sie versuchen, ohne entsprechende Zugriffsberechtigungen auf eine Datei oder ein Verzeichnis zuzugreifen. In diesem Fall löst Python die Ausnahme PermissionError aus, um Sie darüber zu informieren, dass Sie nicht über die erforderlichen Berechtigungen verfügen.

Angenommen, Sie arbeiten auf einem Unix-ähnlichen System wie Linux oder macOS. Sie möchten den Inhalt der Datei /etc/hosts aktualisieren. In Unix-ähnlichen Systemen kann nur der Root-Benutzer diese Datei ändern. Wenn Sie also versuchen, Ihre Aufgabe mit einem anderen Benutzer auszuführen, erhalten Sie eine Fehlermeldung:

>>> with open("/etc/hosts", mode="a") as file:
...     print(file.write("##"))
...
Traceback (most recent call last):
  File "<input>", line 1, in <module>
    with open("/etc/hosts", mode="a") as file:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
PermissionError: [Errno 13] Permission denied: '/etc/host'

Dieser Fehler tritt auf, weil die Datei /etc/hosts eine Systemdatei ist. Sie benötigen Root-Rechte, um diese Datei zu ändern. Ihr Code versucht, die Datei zum Anhängen von Inhalten zu öffnen, ohne über die erforderlichen Berechtigungen zu verfügen, was zu einer PermissionError-Ausnahme führt.

Abstrakte klassenbezogene Ausnahme: NotImplementedError

Manchmal möchten Sie eine benutzerdefinierte Basisklasse mit einer vordefinierten Schnittstelle erstellen, von der Ihre Benutzer ihre eigenen Klassen ableiten können. Auf diese Weise stellen Sie sicher, dass die Unterklassen die erforderliche Schnittstelle erfüllen. In Python können Sie dies mithilfe einer sogenannten abstrakten Basisklasse (ABC) tun.

Das Modul abc in der Standardbibliothek stellt die Klasse ABC und andere verwandte Tools bereit, mit denen Sie benutzerdefinierte Basisklassen definieren können, die eine bestimmte Schnittstelle definieren. Beachten Sie, dass Sie ABCs nicht direkt instanziieren können. Sie sollen in Unterklassen unterteilt werden.

Wenn Sie mit der Erstellung Ihrer ABCs beginnen, werden Sie feststellen, dass es beim Definieren von Methoden üblich ist, eine NotImplementedError-Ausnahme für die Methoden auszulösen, die die Unterklassen implementieren sollten, aber keine strenge Anforderung darstellen.

Angenommen, Sie möchten eine Klassenhierarchie erstellen, um verschiedene Vögel darzustellen, beispielsweise eine Ente, einen Schwan, einen Pinguin usw. Sie entscheiden, dass alle Klassen über die Methoden .swim() und .fly() verfügen sollen. In dieser Situation können Sie mit der folgenden Basisklasse beginnen:

from abc import ABC

class Bird(ABC):
    def swim(self):
        raise NotImplementedError("must be implemented in subclasses")

    def fly(self):
        raise NotImplementedError("must be implemented in subclasses")

In dieser Bird-Klasse erben Sie von abc.ABC, was bedeutet, dass Sie eine abstrakte Basisklasse erstellen. Anschließend definieren Sie die Methoden .swim() und .fly(), die die Ausnahme NotImplementedError mit einer entsprechenden Fehlermeldung auslösen.

Hier ist ein Beispiel dafür, wie Sie konkrete Vögel aus der oben genannten Klasse ableiten können:

# ...

class Duck(Bird):
    def swim(self):
        print("The duck is swimming")

    def fly(self):
        print("The duck is flying")

class Penguin(Bird):
    def swim(self):
        print("The penguin is swimming")

In diesem Beispiel erstellen Sie die Klasse Duck mit den Methoden .swim() und .fly(). Anschließend erstellen Sie die Klasse Penguin, die nur über die Methode .swim() verfügt, da Pinguine nicht fliegen können. Sie können die Klasse Duck normal verwenden. Im Gegensatz dazu verhält sich die Klasse Penguin anders, wenn Sie ihre Methode .fly() aufrufen:

>>> from birds import Duck

>>> donald = Duck()
>>> donald.swim()
The duck is swimming
>>> donald.fly()
The duck is flying

>>> skipper = Penguin()
>>> skipper.swim()
The penguin is swimming
>>> skipper.fly()
Traceback (most recent call last):
    ...
NotImplementedError: must be implemented in subclasses

In diesem Codeausschnitt funktioniert die Klasse Duck wie erwartet. Unterdessen löst die Klasse Penguin einen NotImplementedError aus, wenn Sie die Methode .fly() für eine ihrer Instanzen aufrufen.

Assertionsfehler: AssertionError

Python verfügt über eine Funktion namens Assertions, die Sie mit der Anweisung assert definieren können. Mit Behauptungen können Sie während der Entwicklung Ihres Codes Zulässigkeitsprüfungen festlegen. Mithilfe von Behauptungen können Sie die Korrektheit Ihres Codes testen, indem Sie prüfen, ob bestimmte Bedingungen weiterhin erfüllt sind. Dies ist praktisch, wenn Sie Ihren Code testen und debuggen.

Die Assert-Anweisung hat die folgende Syntax:

assert expression[, assertion_message]

Der Teil expression ist eine Bedingung, die wahr sein sollte, es sei denn, Ihr Programm weist einen Fehler auf. Wenn die Bedingung falsch wird, löst die Behauptung eine AssertionError-Ausnahme aus und beendet die Ausführung Ihres Programms.

Behauptungen sind nützlich zum Schreiben von Testfällen. Sie können sie verwenden, um Annahmen wie Vorbedingungen und Nachbedingungen zu überprüfen. Sie können beispielsweise testen, ob ein Argument von einem bestimmten Typ ist, Sie können den Rückgabewert einer Funktion testen und so weiter. Diese Prüfungen können Ihnen dabei helfen, Fehler bei der Entwicklung eines Programms so schnell wie möglich zu erkennen.

Angenommen, Sie befinden sich in einem Interview zum Python-Programmieren. Sie werden gebeten, eine Funktion zu implementieren, die die FizzBuzz-Herausforderung meistert, wobei Sie "fizz" für durch drei teilbare Zahlen, "buzz" für durch fünf teilbare Zahlen und zurückgeben "fizz Buzz" für diejenigen, die sowohl durch drei als auch durch fünf teilbar sind. Sie schreiben eine Funktion wie die folgende:

def fizzbuzz(number):
    if number % 3 == 0:
        return "fizz"
    elif number % 5 == 0:
        return "buzz"
    elif number % 15 == 0:
        return "fizz buzz"
    else:
        return number

Diese Funktion deckt offenbar alle möglichen Szenarien ab. Sie beschließen jedoch, einige grundlegende Tests zu schreiben, um sicherzustellen, dass die Funktion ordnungsgemäß funktioniert. Am Ende Ihrer fizzbuzz.py-Datei erhalten Sie den folgenden Code:

# ...

if __name__ == "__main__":
    assert fizzbuzz(9) == "fizz"
    assert fizzbuzz(10) == "buzz"
    assert fizzbuzz(15) == "fizz buzz"
    assert fizzbuzz(7) == 7
    print("All tests pass")

In diesem Codeausschnitt haben Sie einige schnelle Behauptungen hinzugefügt, um zu überprüfen, ob Ihre Funktion bei unterschiedlichen Eingabewerten die richtige Zeichenfolge zurückgibt. Jetzt können Sie den Test ausführen, indem Sie die Datei über die Befehlszeile ausführen:

$ python fizzbuzz.py
Traceback (most recent call last):
  File ".../fizzbuzz.py", line 26, in <module>
    assert fizzbuzz(15) == "fizz buzz"
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

Wow! Sie haben eine AssertionError-Ausnahme erhalten, was bedeutet, dass einige der Tests fehlgeschlagen sind. Wenn Sie sich den Ausnahme-Traceback ansehen, stellen Sie fest, dass die Behauptung fehlschlägt, wenn Sie die Funktion mit 15 als Argument aufrufen. Diese Zahl ist durch 3 und durch 5 teilbar, daher ist die aktuelle Reihenfolge Ihrer Bedingungen falsch.

Sie müssen die Bedingung Nummer % 15 == 0 an die erste Position verschieben:

def fizzbuzz(number):
    if number % 15 == 0:
        return "fizz buzz"
    elif number % 3 == 0:
        return "fizz"
    elif number % 5 == 0:
        return "buzz"
    else:
        return number

# ...

Die Bedingungen prüfen zunächst, ob die eingegebene Zahl durch 3 und 5 teilbar ist. Fahren Sie nun fort und führen Sie die Datei erneut aus:

$ python fizzbuzz.py
All tests pass

Großartig! Alle Ihre Tests bestehen. Die Funktion erledigt ihre Aufgabe korrekt. Das ist die Stärke der assert-Anweisung.

Beachten Sie abschließend, dass Sie die Ausnahme AssertionError in Ihrem Code nicht explizit auslösen sollten. Stattdessen sollten Sie zulassen, dass die Anweisung assert diese Ausnahme auslöst, wenn die Bedingung der Behauptung fehlschlägt. Darüber hinaus sollten Sie nicht versuchen, Fehler zu behandeln, indem Sie Code schreiben, der die Ausnahme AssertionError abfängt, da Assertionen deaktiviert werden können.

Interpreter-Exit-Ausnahmen

Beim Schreiben von Python-Code werden Sie auf Situationen stoßen, in denen Sie eine laufende Anwendung oder ein laufendes Programm beenden müssen.

Wenn beispielsweise während der Ausführung einer App ein Fehler auftritt, können Sie entscheiden, die App sauber mit einem entsprechenden Exit-Status zu beenden, was bei Befehlszeilen-Apps hilfreich sein kann. Ein weiteres Beispiel wäre, wenn Sie Code testen, dessen Ausführung zu lange dauert oder der irgendwie hängen bleibt. In diesem Fall möchten Sie die Ausführung des Codes schnell beenden.

Python verfügt über die folgenden Ausnahmen, die diese Situationen behandeln:

    SystemExit
    KeyboardInterrupt

Im Allgemeinen sollte Ihr Code diese Ausnahmen nicht abfangen oder behandeln. Dies kann dazu führen, dass Sie Ihr Programm nicht beenden können, sodass es unmöglich ist, es aus dem Code heraus oder über die Tastatur zu beenden.

In den folgenden Abschnitten erfahren Sie, wann diese Ausnahmen in Ihrem Python-Code auftreten können. Sie werden auch einige Beispiele schreiben, die ihre Verwendung veranschaulichen.

SystemExit

Python löst die Ausnahme SystemExit aus, wenn Sie die Funktion sys.exit() in Ihrem Code aufrufen. Wenn Sie die Ausnahme nicht behandeln, wird der Python-Interpreter beendet, ohne einen Ausnahme-Traceback auszugeben:

>>> import sys
>>> sys.exit(0)
$

In diesem Beispiel rufen Sie sys.exit() auf, um den Python-Interpreter zu beenden. Dieser Anruf führt Sie zurück zu Ihrer Terminalsitzung.

In der Praxis können Sie SystemExit direkt verwenden, wenn Sie eine App beenden müssen. Angenommen, Sie möchten eine minimale CLI-App (Befehlszeilenschnittstelle) erstellen, die die Grundfunktionalität des Unix-Befehls ls nachahmt, der den Inhalt eines bestimmten Verzeichnisses auflistet.

In dieser Situation können Sie ein Skript wie das folgende schreiben:

import sys
from pathlib import Path

if (args_count := len(sys.argv)) > 2:
    print(f"One argument expected, got {args_count - 1}")
    raise SystemExit(2)
elif args_count < 2:
    print("You must specify the target directory")
    raise SystemExit(2)

target_dir = Path(sys.argv[1])

if not target_dir.is_dir():
    print("The target directory doesn't exist")
    raise SystemExit(1)

for entry in target_dir.iterdir():
    print(entry.name)

Dieses Programm verarbeitet die in der Befehlszeile bereitgestellten Argumente, die automatisch in der Variablen sys.argv gespeichert werden. Das erste Element in sys.argv ist der Name des Programms. Das zweite Element sollte das Zielverzeichnis sein.

Die App sollte nur ein Zielverzeichnis akzeptieren, daher darf die Variable args_count höchstens 2 sein. Wenn die App mehr als ein Zielverzeichnis erhält, geben Sie eine Fehlermeldung aus und lösen eine SystemExit-Ausnahme mit dem Exit-Status 2 aus. Dies weist darauf hin, dass die App nach einem Fehler beendet wurde.

Der Zweig elif prüft, ob der Benutzer ein Zielverzeichnis angegeben hat. Ist dies nicht der Fall, geben Sie dem Benutzer eine Fehlermeldung aus und beenden die App, wodurch eine SystemExit-Ausnahme ausgelöst wird.

Nachdem Sie den Inhalt von sys.argv überprüft haben, erstellen Sie ein pathlib.Path-Objekt, um den Pfad zu Ihrem Zielverzeichnis zu speichern. Wenn dieses Verzeichnis nicht existiert, informieren Sie den Benutzer und beenden die App erneut mit der Ausnahme SystemExit. Diesmal ist der Exit-Status 1, um zu signalisieren, dass bei der Ausführung der App ein Fehler aufgetreten ist. Schließlich listet die for-Schleife den Verzeichnisinhalt auf, einen Eintrag pro Zeile.

Auf einem Unix-ähnlichen System wie Linux und macOS können Sie den folgenden Befehl ausführen, um zu überprüfen, wie das Skript funktioniert:

$ python ls.py
You must specify the target directory
$ echo $?
2

$ python ls.py /home /etc
One argument expected, got 2
$ echo $?
2

$ python ls.py .
hello.py
birds.py
grades.py
greeting.py
fizzbuzz.py
ls.py
mean.py
stack.py
square.py
rainbow.py
$ echo $?
0

Wenn Sie das Skript ohne Argument ausführen, erhalten Sie eine Meldung, dass Sie ein Zielverzeichnis angeben müssen. Wenn Sie den Befehl echo verwenden, um den Exit-Code, dargestellt durch $?, zu überprüfen, werden Sie sehen, dass es sich um 2 handelt. Im zweiten Beispiel geben Sie zwei Zielverzeichnisse an. Auch hier schlägt die App mit einer Fehlermeldung fehl. Der Befehl echo gibt auch 2 zurück.

Abschließend führen Sie das Skript mit dem aktuellen Arbeitsverzeichnis als Argument aus. In diesem Fall erhalten Sie die Liste der Dateien, die sich in diesem Verzeichnis befinden. Wenn Sie echo ausführen, erhalten Sie den Exit-Status 0, der signalisiert, dass die Ausführung der App erfolgreich war.

KeyboardInterrupt

Die KeyboardInterrupt-Ausnahme unterscheidet sich etwas von anderen Ausnahmen. Python löst diese Ausnahme aus, wenn der Benutzer absichtlich die Tastenkombination Strg<span>+C drückt während der Ausführung eines Programms. Diese Aktion unterbricht ein laufendes Programm.

Angenommen, Sie arbeiten an einem Codeabschnitt, der eine Schleife enthält. Aus Versehen gerät der Code in eine Endlosschleife. In dieser Situation benötigen Sie eine schnelle Möglichkeit, die Ausführung des Codes zu beenden. Dann ist die Tastenkombination Strg<span>+C praktisch.

Betrachten Sie die folgende Spielzeugschleife:

>>> while True:
...     print("Hello")
...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Traceback (most recent call last):
    ...
KeyboardInterrupt

Diese Schleife ist absichtlich so geschrieben, dass sie unendlich ist. In der Praxis kann es zu echten Schleifen kommen, die aufgrund eines logischen Fehlers in eine unendliche Iteration übergehen. Wenn dieses Problem auftritt, können Sie die Tasten Strg<span>+C drücken Beenden Sie die Ausführung des Codes. Infolgedessen löst Python eine KeyboardInterrupt-Ausnahme aus.

Abschließend ist es wichtig zu beachten, dass Sie diese Ausnahme nicht in Ihrem Code abfangen sollten, da dies dazu führen kann, dass der Interpreter nicht beendet wird.

Ausnahmegruppen

In Python 3.11 und höher gibt es die Klassen ExceptionGroup und BaseExceptionGroup. Sie können sie verwenden, wenn Sie mehrere unabhängige Ausnahmen gleichzeitig auslösen müssen. Der Unterschied zwischen diesen Klassen besteht darin, dass BaseExceptionGroup BaseException erweitert, während ExceptionGroup Exception erweitert.

Sie können auf diese Ausnahmen zurückgreifen, wenn ein asynchrones Programm mehrere gleichzeitige Aufgaben hat, die gleichzeitig fehlschlagen könnten. Aber im Allgemeinen werden Sie eine ExceptionGroup sparsam auslösen.

Sie können Ausnahmegruppen nach Bedarf bearbeiten und auslösen. So fangen Sie eine Ausnahmegruppe mit der zugehörigen exclusive*-Syntax ab:

>>> try:
...     raise ExceptionGroup(
...         "several exceptions",
...         [
...             ValueError("invalid value"),
...             TypeError("invalid type"),
...             KeyError("missing key"),
...         ],
...     )
... except* ValueError:
...     print("Handling ValueError")
... except* TypeError:
...     print("Handling TypeError")
... except* KeyError:
...     print("Handling KeyError")
...
Handling ValueError
Handling TypeError
Handling KeyError

Mit der exclusive*-Syntax können Sie einzelne Ausnahmen in einer Ausnahmegruppe abfangen. Auf diese Weise können Sie einzelne Ausnahmen gezielt behandeln.

Abschluss

Sie haben etwas über die integrierten Ausnahmen von Python erfahren, die eine schnelle und effiziente Möglichkeit bieten, Fehler und Ausnahmesituationen in Ihrem Code zu behandeln. Jetzt kennen Sie die am häufigsten verwendeten integrierten Ausnahmen, wissen, wann sie auftreten und wie Sie sie in Ihrem Ausnahmebehandlungscode verwenden. Sie haben außerdem erfahren, dass Sie diese Ausnahmen in Ihrem Code auslösen können.

In diesem Tutorial haben Sie:

  • Erfahren Sie, was Fehler und Ausnahmen in Python sind
  • Verstanden, wie Python die eingebauten Ausnahmen in einer Klassenhierarchie organisiert
  • Untersucht die am häufigsten verwendeten integrierten Ausnahmen
  • Erfahren Sie, wie Sie in Ihrem Code integrierte Ausnahmen behandeln und auslösen

Dieses Wissen hilft Ihnen, Ihren Code effizient zu debuggen, da jede Ausnahme eine bestimmte Bedeutung und einen bestimmten Anwendungsfall hat. Sie werden außerdem in der Lage sein, integrierte Ausnahmen in Ihrem Code effektiv zu behandeln und auszulösen, was für einen Python-Entwickler eine großartige Fähigkeit ist.