Python #21 – Exceptionhandling

In diesem Beitrag möchte ich dir zeigen wie du dein Programm robust schreiben kannst und auf eventuell auftretenne Fehler reagieren kannst. Die Fehlerbehandlung in Pythonskripten habe ich bereits im Beitrag Python #8: Fehlerbehandlung behandelt, jedoch nicht ausführlich genug und daher hier nun deutlich ausführlicher!

Was ist ein Fehler?

Ein Fehler oder auch Bug genannt ist ein Fehlverhalten einer Anwendung. Dabei muss man unterscheiden zwischen Programmierfehler (nicht oder nur teilweise umgesetzte Story) und Eingabefehler durch den Benutzer. Wobei letzteres auch wieder nicht korrekt durch den Programmierer abgefangen wurde (ggf. eine gap in der Anforderung).

Wie sollte auf einen Fehler reagiert werden?

Wie man auf einen Fehler reagiert ist immer abhängig ob andere Prozesse von dem Ergebnis abhängig sind und ob die Anwendung auch mit diesem Ereignis für den Benutzer weitergeführt werden kann. Kurzum wenn ein Fehler auftritt sollte eine Entsprechende Meldung an den Benutzer erfolgen das ein Fehler aufgetreten ist.

Wenn es ein schwerwiegender Fehler ist sollte das Programm an der Stelle beendet werden! Im Idealfall wird die Anwendung beim erneuten starten an der Stelle fortfahren. Dieses kann zbsp. gemacht werden wenn das Programm eine Datei benötigt welche beim ersten Durchlauf nicht zur Verfügung stand.

ein einfaches Beispiel

Hier nun ein kleines Beispiel wie ein Fehler auftreten kann.

zahl1 = 5
zahl2 = 0
ergebnis = zahl1 / zahl2
print(ergebnis)

Was passiert wenn man 5 durch 0 teilt? Richtig! Ein Fehler, denn Teilen durch 0 ist nicht möglich.

Im nachfolgenden Stacktrace wird aufgezeigt welcher Fehler aufgetreten ist, sowie an welcher Stelle im Quellcode.

---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-2-f73501945a8c> in <module>()
      1 zahl1 = 5
      2 zahl2 = 0
----> 3 ergebnis = zahl1 / zahl2
      4 print(ergebnis)

ZeroDivisionError: division by zero

Für den technisch nicht versierten Benutzer der Anwendung ist dieser Fehler nicht sehr hilfreich. Man sollte also nun diesen Fehler abfangen und eine „vernünftige“ Fehlermeldung ausgeben.

Abfangen der Exception „division by zero“

Wollen wir zunächst die Exception abfangen, dazu packen wir unser Programm in ein Try-Except Block. Der Block beginnt mit einem „try:“, in diesen Bereich kommt der Code welcher ggf. einen Fehlerfall erzeugen kann. Im Bereich „except“ definieren wir die ggf. auftretene Exception. In unserem Fall ist es der „ZeroDivisionError“, zusätzlich kann man diese Exception auf in eine Variable legen um dann auf Wert wie die Message, Argumente usw. zugreifen zu können.

try:
    zahl1 = 5
    zahl2 = 0
    ergebnis = zahl1 / zahl2
    print(ergebnis)
except ZeroDivisionError as error:
    print("Error:", error)

Wenn wir nun den Code ausführen wir der Fehler abgefangen und eine etwas bessere Meldung ausgegeben:

Error: division by zero

Jedoch haben wir nur diese eine Exception abgehandelt es kann nun natürlich auch eine andere Exception auftreten welche dann wieder abgefangen werden muss.

Abfangen von mehreren Exceptions

Im ersten Beispiel haben wir eine Exception vom Typ „ZeroDivisionError“ ausgelöst. Wenn man nun mehr als eine Exception erwartet so kann man diese mit einer Klammer und Kommaseparariert aufführen.

try:
    zahl1 = 5
    zahl2 = 1
    ergebnis = zahl1 / zahl2
    raise NameError('Hallo Welt!')
    print(ergebnis)
except (ZeroDivisionError, NameError) as error:
    print("Error:", error)

Mit dem Befehl „raise“ können wir eine Exception werfen, dieses kann man zbsp. machen wenn eine Bedingung nicht erfüllt ist und die Ausführung abgebrochen werden soll.

Benutzereingaben validieren

Nehmen wir nun unser kleines Programm und erweitern dieses um die Fähigkeit das der Benutzer die Zahl selber eingeben kann, ABER wir wollen nur Zahlen kleiner gleich 5 verarbeiten. Dieses prüfen wir mit einer Bedingten Anweisung. Wenn die eingegebene Zahl kleiner gleich 5 ist werfen wir eine Exception und berechen das Programm ab.

try:
    zahl1 = int(input("Eine Zahl <= 5 "))
    zahl2 = 1
    ergebnis = zahl1 / zahl2
    print(ergebnis)
    if(ergebnis > 5):
        raise NameError('Zahl ist größer als 5')
except (ZeroDivisionError, NameError) as error:
    print("Error:", error)

Wenn der Code ausgeführt wird, kann man nun nun eine Eingabe tätigen. Wie bereits erwähnt erwarten wir eine Zahl kleiner gleich 5.

Wenn jetzt aber der Benutzer einen Buchstaben eingibt erhält man eine andere Exception welche wir bisher nicht behandelt haben.

Python3 - Exceptionhandling, ValueError beim umwandeln von String nach Integer
Python3 – Exceptionhandling, ValueError beim umwandeln von String nach Integer

In der Zeile 2 nehmen wir die Eingabe auf der Konsole entgegen und wandeln diese ohne weitere Prüfung in eine Zahl um hier müßte also zusätzlich geprüft werden ob der Benutzer eine Zahl eingegeben hat. Oder wir reagieren auf einen ValueError.

try:
    zahl1 = int(input("Eine Zahl <= 5 "))
    zahl2 = 1
    ergebnis = zahl1 / zahl2
    print(ergebnis)
    if(ergebnis > 5):
        raise NameError('Zahl ist größer als 5')
except (ZeroDivisionError, NameError) as error:
    print("Error:", error)
except ValueError as valueError:
    print("Fehler bei der Eingabe!")

Wir haben nun einen zusätzlichen Zweig für den ValueError hinzugefügt. Wenn also ein ValueError auftritt wird der Text Fehler bei der Eingabe!“ ausgegeben. Zusätzlich sollten wir jedoch den eingegebenen Text validieren und somit den Quellcode deutlich robuster gestalten.

try:
    eingabe = input("Eine Zahl <= 5 ")
    if not eingabe.isdigit():
        raise ValueError("Die Eingabe ist keine Zahl!")
    zahl1 = int(eingabe)
    zahl2 = 1
    ergebnis = zahl1 / zahl2
    print(ergebnis)
    if(ergebnis > 5):
        raise NameError('Zahl ist größer als 5')
except (ZeroDivisionError, NameError) as error:
    print("Error:", error)
except ValueError as valueError:
    print(valueError)
Eine Zahl <= 5 g
Die Eingabe ist keine Zahl!

eigene Exceptions erstellen

In den zuvor gezeigten Quellcodes haben wir die ValueError, NameError und ZeroDivisionError verwendet. Es gibt aber auch fälle da gibt es keine passende Exception zbsp. wenn ein Wert nicht wie erwartet ist. Im nachfolgenden soll der Benutzer eine Zahl zwischen 0 und 100 eingeben also alles unter 0  und größer als 100 sind nicht valide Werte und das Programm soll vorzeitig beendet werden.

Zunächst erstellen wir und unsere eigene Exception, ich wähle hier den Namen „OutOfBoundException“ denn der Zahlenwert ist ja nicht zwischen den beiden gewählten bereichen.

class OutOfBoundsException(Exception):
    
    def __init__(self, message):
        self.message = message

Nach der Validierung ob die Eingabe eine Zahl ist, wird also nun geprüft ob der Wert zwischen 0 und 100 liegt wenn dieses nicht so ist wird unsere CustomException gworfen.

if zahl < 0  or zahl > 100:
       raise(OutOfBoundsException("Fehler! Die Zahl muss zwischen 0 und 100 liegen!"))

Hier nun das kleine Programm zum prüfen einer Eingabe auf Zahl und der Wert zwischen 0 und 100.

class OutOfBoundsException(Exception):
    
    def __init__(self, message):
        self.message = message
                
try:
    eingabe = input("Eine Zahl >= 0 & <= 100 ")
    if not eingabe.isdigit():
        raise ValueError("Die Eingabe ist keine Zahl!")
    zahl = int(eingabe)
    if zahl < 0  or zahl > 100:
        raise(OutOfBoundsException("Fehler! Die Zahl muss zwischen 0 und 100 liegen!"))
except ValueError as valueError:
    print(valueError)
except OutOfBoundsException as oObException:
    print(oObException

 

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.