Python Exception Handling

PythonBeginner
Jetzt üben

Einführung

In der Informatik und Programmierung ist die Ausnahmebehandlung (Exception Handling) der Prozess, bei dem auf das Auftreten von Ausnahmen reagiert wird – also auf anomale oder außergewöhnliche Bedingungen, die eine spezielle Verarbeitung erfordern. Python verfügt über viele integrierte Exceptions, die ausgelöst werden, wenn ein Programm auf einen Fehler stößt. Darüber hinaus enthalten viele externe Bibliotheken eigene benutzerdefinierte Exceptions, die Sie ebenfalls behandeln müssen.

In diesem Lab lernen Sie die Grundlagen der Ausnahmebehandlung in Python. Sie beginnen mit einfachen try- und except-Blöcken, gehen über zur Behandlung mehrerer Exceptions, verstehen die Verwendung des finally-Blocks und erstellen und verwalten schließlich Ihre eigenen benutzerdefinierten Exceptions.

Grundlegende Ausnahmebehandlung

In diesem Schritt lernen Sie die Grundlagen der Ausnahmebehandlung in Python mithilfe von try- und except-Blöcken kennen.

Es ist ein mathematisches Faktum, dass man nicht durch Null teilen kann. Wenn Sie dies in Python versuchen, löst der Interpreter einen integrierten ZeroDivisionError aus. Lassen Sie uns das in der Praxis sehen.

Hinweis: Wenn Sie mit der WebIDE (ähnlich wie VS Code) noch nicht vertraut sind, lernen Sie diese bitte zuerst in diesem Lab kennen.

Öffnen Sie zunächst die Datei basic_handler.py im Dateiexplorer auf der linken Seite und fügen Sie den folgenden Code hinzu. Dies definiert eine einfache Divisionsfunktion.

def divide(dividend , divisor):
    print(dividend / divisor)

divide(dividend=10, divisor=5)

Führen Sie nun das Skript über das Terminal aus:

python3 basic_handler.py

Sie werden die korrekte Ausgabe sehen:

2.0

Sehen wir uns nun an, was passiert, wenn wir versuchen, durch Null zu teilen. Ändern Sie die letzte Zeile in basic_handler.py, um divide mit einem Divisor von 0 aufzurufen:

def divide(dividend , divisor):
    print(dividend / divisor)

divide(dividend=10, divisor=0)

Führen Sie das Skript erneut aus:

python3 basic_handler.py

Diesmal stürzt das Programm ab und gibt einen Traceback aus, der auf einen ZeroDivisionError hinweist:

Traceback (most recent call last):
  File "/home/labex/project/basic_handler.py", line 4, in <module>
    divide(dividend=10, divisor=0)
  File "/home/labex/project/basic_handler.py", line 2, in divide
    print(dividend / divisor)
ZeroDivisionError: division by zero

Um zu verhindern, dass das Programm abstürzt, und stattdessen eine benutzerfreundliche Meldung anzuzeigen, können wir die Exception mit try und except "behandeln". Der Code, der einen Fehler verursachen könnte, wird in den try-Block gesetzt, und der Code, der bei Auftreten dieses Fehlers ausgeführt werden soll, kommt in den except-Block.

Aktualisieren Sie die Datei basic_handler.py mit dem folgenden Code, um den ZeroDivisionError elegant zu behandeln:

## try-except: Ausnahmen elegant behandeln
def divide(dividend , divisor):
    try:  ## Versuche, diesen Code auszuführen
        print(dividend / divisor)
    except ZeroDivisionError:  ## Fange einen spezifischen Ausnahmetyp ab
        print('You can not divide by 0')

divide(dividend=10, divisor=0)

Führen Sie das Skript nun noch einmal aus:

python3 basic_handler.py

Anstatt abzustürzen, gibt das Programm nun die von Ihnen definierte hilfreiche Meldung aus und die Ausführung endet normal:

You can not divide by 0

Behandlung mehrerer Ausnahmen in einem Block

In diesem Schritt erfahren Sie, wie Sie mehrere verschiedene Ausnahmetypen innerhalb eines einzigen except-Blocks behandeln können. Dies ist nützlich, um Ihren Fehlerbehandlungscode zu optimieren, wenn mehrere Arten von Fehlern auftreten können.

Sie können ein Tupel von Ausnahmen abfangen, wie z. B. (ZeroDivisionError, TypeError), um sie mit derselben Logik zu behandeln.

Öffnen Sie die Datei multiple_handler.py und fügen Sie den folgenden Code hinzu. Diese Funktion ist so konzipiert, dass sie potenziell entweder einen TypeError (durch den Versuch, einen String und eine Ganzzahl zu verketten) oder einen ZeroDivisionError auslöst.

## Mehrere Ausnahmen in einem except-Block behandeln
def divide(dividend , divisor):
    try:
        if (dividend == 10):
          var = 'str' + 1  ## Dies löst einen TypeError aus
        else:
          print(dividend / divisor)
    except (ZeroDivisionError, TypeError) as error:  ## Fange mehrere Ausnahmetypen ab
        print(error)  ## Gib die Fehlermeldung aus

divide(dividend=20, divisor=5)

Lassen Sie uns den Code zunächst in einem Szenario ausführen, in dem keine Ausnahme auftritt. Führen Sie das Skript aus:

python3 multiple_handler.py

Die Ausgabe ist das Ergebnis der Division:

4.0

Lassen Sie uns nun den TypeError auslösen. Ändern Sie die letzte Zeile von multiple_handler.py, um 10 als Dividenden zu verwenden:

## ... (rest of the code) ...
divide(dividend=10, divisor=5)

Führen Sie das Skript erneut aus:

python3 multiple_handler.py

Der except-Block fängt den TypeError ab und gibt die zugehörige Fehlermeldung aus:

can only concatenate str (not "int") to str

Lassen Sie uns schließlich den ZeroDivisionError auslösen. Ändern Sie die letzte Zeile erneut und versuchen Sie diesmal, durch Null zu teilen. Beachten Sie, dass die TypeError-Bedingung (dividend == 10) nicht erfüllt ist.

## ... (rest of the code) ...
divide(dividend=20, divisor=0)

Führen Sie das Skript aus:

python3 multiple_handler.py

Derselbe except-Block fängt nun den ZeroDivisionError ab und gibt seine Meldung aus:

division by zero

Damit die Überprüfung erfolgreich ist, stellen Sie bitte sicher, dass der letzte Aufruf in Ihrem Skript divide(dividend=10, divisor=5) lautet, um den TypeError auszulösen.

Der Finally-Block bei der Ausnahmebehandlung

In diesem Schritt lernen Sie den Zweck und die Verwendung des finally-Blocks kennen. Der Code innerhalb einer finally-Klausel wird immer ausgeführt, unabhängig davon, ob eine Ausnahme ausgelöst oder behandelt wurde. Dies macht ihn ideal für Aufräumarbeiten, wie das Schließen einer Datei oder einer Netzwerkverbindung.

Sehen wir uns an, wie es funktioniert. Öffnen Sie die Datei finally_handler.py und fügen Sie den folgenden Code hinzu:

## finally-Block: wird unabhängig von Ausnahmen immer ausgeführt
def divide(dividend , divisor):
    try:
        print(dividend / divisor)
    except ZeroDivisionError:
        print('You can not divide by 0')
    finally:  ## Wird immer ausgeführt, auch wenn eine Ausnahme auftritt
        print('Execution finished')

divide(dividend=10, divisor=5)

Führen Sie das Skript über Ihr Terminal aus:

python3 finally_handler.py

In diesem Fall tritt keine Ausnahme auf. Der try-Block wird erfolgreich abgeschlossen, und dann wird der finally-Block ausgeführt.

2.0
Execution finished

Lassen Sie uns nun einen Fehler einbauen. Ändern Sie die letzte Zeile in finally_handler.py, um durch Null zu teilen:

## ... (rest of the code) ...
divide(dividend=10, divisor=0)

Führen Sie das Skript erneut aus:

python3 finally_handler.py

Diesmal wird ein ZeroDivisionError ausgelöst und vom except-Block abgefangen. Obwohl eine Ausnahme aufgetreten ist, wird der finally-Block nach Abschluss des except-Blocks weiterhin ausgeführt.

You can not divide by 0
Execution finished

Wie Sie sehen können, wird die Meldung "Execution finished" in beiden Szenarien ausgegeben, was zeigt, dass der finally-Block ein zuverlässiger Ort für Code ist, der immer ausgeführt werden muss.

Benutzerdefinierte Ausnahmen

In diesem Schritt lernen Sie, wie Sie Ihre eigenen benutzerdefinierten Ausnahmen erstellen. Dies ist eine leistungsstarke Funktion, um Ihre Anwendungen lesbarer und wartbarer zu machen, da Sie spezifische Fehlertypen erstellen können, die Probleme beschreiben, die für die Domäne Ihres Programms einzigartig sind.

Benutzerdefinierte Ausnahmen werden definiert, indem eine neue Klasse erstellt wird, die von Pythons Basisklasse Exception erbt. Sie können diese Ausnahme dann mit dem Schlüsselwort raise auslösen.

Öffnen Sie die Datei custom_exception.py und fügen Sie den folgenden Code hinzu, um eine einfache benutzerdefinierte Ausnahme zu definieren und auszulösen:

## Benutzerdefinierte Ausnahme: Erstellung durch Vererbung von der Exception-Klasse
class MyCustomException(Exception):
    pass

raise MyCustomException  ## Löse die benutzerdefinierte Ausnahme aus

Wenn Sie dieses Skript ausführen, wird es sofort angehalten und einen Traceback für Ihre neue Ausnahme anzeigen:

python3 custom_exception.py
Traceback (most recent call last):
  File "/home/labex/project/custom_exception.py", line 5, in <module>
    raise MyCustomException  ## Löse die benutzerdefinierte Ausnahme aus
__main__.MyCustomException

Sie können auch eine beschreibende Meldung angeben, wenn Sie eine benutzerdefinierte Ausnahme auslösen. Ändern Sie custom_exception.py, um einen String an Ihre Ausnahme zu übergeben:

class MyCustomException(Exception):
    pass

raise MyCustomException('A custom message for my custom exception')

Die Ausführung zeigt Ihre Meldung im Traceback:

Traceback (most recent call last):
  File "/home/labex/project/custom_exception.py", line 4, in <module>
    raise MyCustomException('A custom message for my custom exception')
__main__.MyCustomException: A custom message for my custom exception

Die Behandlung einer benutzerdefinierten Ausnahme erfolgt auf die gleiche Weise wie bei einer integrierten Ausnahme: mithilfe eines try...except-Blocks. Aktualisieren Sie custom_exception.py auf die endgültige Form, die die benutzerdefinierte Ausnahme auslöst und behandelt:

class MyCustomException(Exception):
    pass

try:
    raise MyCustomException('A custom message for my custom exception')
except MyCustomException:
    print('My custom exception was raised')

Führen Sie das Skript nun ein letztes Mal aus:

python3 custom_exception.py

Das Programm stürzt nicht mehr ab. Stattdessen führt es den Code im except-Block aus und gibt Ihre Bestätigungsmeldung aus:

My custom exception was raised

Zusammenfassung

In diesem Lab haben Sie die wesentlichen Techniken zur Behandlung von Ausnahmen in Python kennengelernt. Sie begannen mit den grundlegenden try- und except-Blöcken, um spezifische Fehler abzufangen und Programmabstürze zu verhindern. Anschließend haben Sie gelernt, wie man effizient mehrere Ausnahmetypen in einem einzigen except-Block behandelt. Sie haben auch den finally-Block erkundet, der für Aufräumcode, der immer ausgeführt werden muss, entscheidend ist. Schließlich haben Sie die Fähigkeit erworben, eigene benutzerdefinierte Ausnahmen zu erstellen, auszulösen und zu behandeln, was es Ihnen ermöglicht, eine robustere und aussagekräftigere Fehlerbehandlungslogik in Ihren Anwendungen aufzubauen.