Articles

Ausnahme- und Fehlerbehandlung in Python

Einführung


Quelle

Bevor wir uns damit beschäftigen, warum die Behandlung von Ausnahmen so wichtig ist und welche Arten voneingebauten Ausnahmen, die Python unterstützt, ist es notwendig zu verstehen, dass es einen feinen Unterschied zwischen einem error und einem exception gibt.

Fehler können nicht behandelt werden, während Python-Exceptions zur Laufzeit behandelt werden können. Ein Fehler kann ein syntax (Parsing-)Fehler sein, während es viele Arten von Ausnahmen geben kann, die während der Ausführung auftreten können und nicht bedingungslos unbehandelbar sind. Ein Error kann auf kritische Probleme hinweisen, die eine vernünftige Anwendung nicht versuchen sollte, abzufangen, während ein Exception Bedingungen anzeigen kann, die eine Anwendung versuchen sollte, abzufangen. Fehler sind eine Form einer ungeprüften Ausnahme und sind wie ein OutOfMemoryError nicht abfangbar, was ein Programmierer nicht versuchen sollte, zu behandeln.

Ausnahmebehandlung macht Ihren Code robuster und hilft, potenzielle Fehler zu vermeiden, die Ihr Programm unkontrolliert zum Stillstand bringen würden. Stellen Sie sich vor, Sie haben einen Code geschrieben, der in der Produktion eingesetzt wird, und trotzdem bricht er aufgrund einer Ausnahme ab. Ihr Kunde würde das nicht gutheißen, also ist es besser, die jeweilige Ausnahme vorher zu behandeln und das Chaos zu vermeiden.

Fehler können von verschiedenen Typen sein:

  • Syntax-Fehler
  • Out of Memory Error
  • Recursion Error
  • Exceptions

Lassen Sie uns diese der Reihe nach betrachten.

Syntax-Fehler

Syntax-Fehler, oft auch als Parsing-Fehler bezeichnet, werden hauptsächlich dann verursacht, wenn der Parser ein syntaktisches Problem in Ihrem Code entdeckt.

Lassen Sie uns ein Beispiel nehmen, um es zu verstehen.

a = 8b = 10c = a b
 File "<ipython-input-8-3b3ffcedf995>", line 3 c = a b ^SyntaxError: invalid syntax

Der obige Pfeil zeigt an, wenn der Parser bei der Ausführung des Codes auf einen Fehler gestoßen ist. Das dem Pfeil vorangestellte Token verursacht den Fehler. Um solche grundlegenden Fehler zu beheben, nimmt Ihnen Python die meiste Arbeit ab, da es für Sie den Dateinamen und die Zeilennummer ausgibt, an der der Fehler aufgetreten ist.

Out of Memory Error

Speicherfehler sind meist abhängig vom Arbeitsspeicher Ihres Systems und hängen mit Heap zusammen. Wenn Sie große Objekte (oder) referenzierte Objekte im Speicher haben, dann werden Sie OutofMemoryError (Quelle) sehen. Dies kann verschiedene Ursachen haben:

  • Benutzung einer 32-Bit-Python-Architektur (die maximale Speicherzuweisung ist sehr gering, zwischen 2GB – 4GB).
  • Laden einer sehr großen Datendatei
  • Ausführen eines Machine Learning/Deep Learning-Modells und vieles mehr.

Den memory-Fehler können Sie mit Hilfe der Ausnahmebehandlung behandeln, einer Fallback-Ausnahme für den Fall, dass dem Interpreter komplett der Speicher ausgeht und er die aktuelle Ausführung sofort beenden muss. In diesen seltenen Fällen löst Python ein OutofMemoryError aus, das es dem Skript erlaubt, sich irgendwie catch aus dem Speicherfehler zu befreien und sich selbst zu retten.

Da sich Python jedoch an die Speicherverwaltungsarchitektur der Sprache C anlehnt (Funktion malloc()), ist es nicht sicher, dass sich alle Prozesse des Skripts erholen – in manchen Fällen führt ein MemoryError zu einem nicht behebbaren Absturz. Daher ist es weder eine gute Praxis noch ratsam, eine Ausnahmebehandlung für einen solchen Fehler zu verwenden.

Recursion Error

Er hängt mit stack zusammen und tritt beim Aufruf von Funktionen auf. Wie der Name schon sagt, tritt der recursion-Fehler auf, wenn zu viele Methoden ineinander ausgeführt werden (eine mit einer unendlichen Rekursion), die durch die Größe des Stacks begrenzt ist.

Alle Ihre lokalen Variablen und die mit dem Methodenaufruf verbundenen Daten werden auf dem Stack abgelegt. Für jeden Methodenaufruf wird ein Stack-Frame erzeugt, und sowohl die lokalen als auch die methodenaufrufrelevanten Daten werden in diesem Stack-Frame abgelegt. Sobald die Ausführung der Methode abgeschlossen ist, wird der Stack-Frame entfernt.

Um diesen Fehler zu reproduzieren, definieren wir eine Funktion recursion, die rekursiv ist, d. h. sie ruft sich selbst immer wieder als Methodenaufruf in einer Endlosschleife auf. Sie werden einen StackOverflow oder einen Rekursionsfehler sehen, weil der Stack-Frame bei jedem Aufruf mit Methodendaten gefüllt wird, aber nicht freigegeben wird.

def recursion(): return recursion()
recursion()
---------------------------------------------------------------------------RecursionError Traceback (most recent call last)<ipython-input-3-c6e0f7eb0cde> in <module>----> 1 recursion()<ipython-input-2-5395140f7f05> in recursion() 1 def recursion():----> 2 return recursion()... last 1 frames repeated, from the frame below ...<ipython-input-2-5395140f7f05> in recursion() 1 def recursion():----> 2 return recursion()RecursionError: maximum recursion depth exceeded

Einrückungsfehler

Einrückungsfehler sind ähnlich wie der Syntaxfehler und fallen darunter. Er bezieht sich jedoch nur auf Einrückungsprobleme im Skript.

So nehmen wir ein kurzes Beispiel, um einen Einrückungsfehler zu verstehen.

for i in range(10):print('Hello world')

 File "<ipython-input-6-628f419d2da8>", line 2 print('Hello world') ^IndentationError: expected an indented block

Ausnahmen

Auch wenn die Syntax einer Anweisung oder eines Ausdrucks korrekt ist, kann sie bei der Ausführung einen Fehler verursachen. Python-Exceptions sind Fehler, die während der Ausführung erkannt werden und nicht unbedingt fatal sind: Sie werden in diesem Tutorial bald lernen, wie man sie in Python-Programmen behandelt. Ein Exception-Objekt wird erzeugt, wenn ein Python-Skript eine Exception auslöst. Wenn das Skript die Ausnahme nicht explizit behandelt, wird das Programm gezwungen, sich abrupt zu beenden.

Die Programme behandeln Ausnahmen in der Regel nicht und führen zu Fehlermeldungen wie hier gezeigt:

Typfehler

a = 2b = 'DataCamp'a + b
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-7-86a706a0ffdf> in <module> 1 a = 2 2 b = 'DataCamp'----> 3 a + bTypeError: unsupported operand type(s) for +: 'int' and 'str'

Nulldivisionsfehler

100 / 0
---------------------------------------------------------------------------ZeroDivisionError Traceback (most recent call last)<ipython-input-43-e9e866a10e2a> in <module>----> 1 100 / 0ZeroDivisionError: division by zero

Es gibt verschiedene Typen von Python-Ausnahmen, und der Typ wird als Teil der Meldung ausgegeben: Die Typen in den beiden obigen Beispielen sind ZeroDivisionError und TypeError. In beiden Fällen wird als Ausnahmetyp der Name der in Python eingebauten Ausnahme gedruckt.

Der verbleibende Teil der Fehlerzeile gibt anhand des Ausnahmetyps Auskunft darüber, was den Fehler verursacht hat.

Lassen Sie uns nun einen Blick auf die in Python eingebauten Ausnahmen werfen.

Eingebaute Ausnahmen


Source

Bevor Sie mit dem Lernen der eingebauten Ausnahmen beginnen, lassen Sie uns noch einmal kurz die vier Hauptkomponenten der Ausnahmebehandlung durchgehen, wie in dieser Abbildung gezeigt.

  • Try: Hier wird der Codeblock ausgeführt, in dem Sie einen Fehler erwarten.
  • Except: Hier definieren Sie den Typ der Ausnahme, die Sie im Try-Block erwarten (eingebaut oder benutzerdefiniert).
  • Else: Wenn es keine Ausnahme gibt, wird dieser Codeblock ausgeführt (betrachten Sie dies als Abhilfe oder Rückfalloption, wenn Sie erwarten, dass ein Teil Ihres Skripts eine Ausnahme erzeugt).
  • Zum Schluss: Unabhängig davon, ob eine Exception vorliegt oder nicht, wird dieser Codeblock immer ausgeführt.

Im folgenden Teil des Tutorials lernen Sie die gängigen Arten von Exceptions kennen und lernen auch, diese mit Hilfe der Exception-Behandlung zu behandeln.

Tastaturunterbrechungsfehler

Die KeyboardInterrupt-Ausnahme wird ausgelöst, wenn Sie versuchen, ein laufendes Programm durch Drücken von ctrl+c oder ctrl+z in einer Befehlszeile zu stoppen oder den Kernel in Jupyter Notebook zu unterbrechen. Manchmal haben Sie vielleicht nicht die Absicht, ein Programm zu unterbrechen, aber aus Versehen passiert es doch. In diesem Fall kann es hilfreich sein, eine Ausnahmebehandlung zu verwenden, um solche Probleme zu vermeiden.

Im folgenden Beispiel wird das Programm eine KeyboardInterrupt-Ausnahme auslösen, wenn Sie die Zelle ausführen und den Kernel unterbrechen.inp = input()Behandeln wir nun die KeyboardInterruptAusnahme.

try: inp = input() print ('Press Ctrl+C or Interrupt the Kernel:')except KeyboardInterrupt: print ('Caught KeyboardInterrupt')else: print ('No exception occurred')
Caught KeyboardInterrupt

Standardfehler

Lassen Sie uns einige der Standardfehler kennenlernen, die normalerweise beim Programmieren auftreten können.

Arithmetischer Fehler

  • Null-Divisions-Fehler
  • Überlauf-Fehler
  • Fließkomma-Fehler

Alle oben genannten Ausnahmen fallen unter die Basisklasse Arithmetic und werden bei Fehlern in arithmetischen Operationen ausgelöst, wie hier besprochen.

Nulldivision

Wenn der Divisor (zweites Argument der Division) oder der Nenner Null ist, dann löst die Resultierende einen Null-Divisionsfehler aus.

try: a = 100 / 0 print (a)except ZeroDivisionError: print ("Zero Division Exception Raised." )else: print ("Success, no error!")
Zero Division Exception Raised.

OverFlow Error

Der Overflow Error wird ausgelöst, wenn das Ergebnis einer arithmetischen Operation außerhalb des Bereichs liegt. OverflowError wird für ganze Zahlen ausgelöst, die außerhalb eines erforderlichen Bereichs liegen.

try: import math print(math.exp(1000))except OverflowError: print ("OverFlow Exception Raised.")else: print ("Success, no error!")
OverFlow Exception Raised.

Assertion Error

Wenn eine Assertion-Anweisung fehlgeschlagen ist, wird ein Assertion Error ausgelöst.

Lassen Sie uns ein Beispiel nehmen, um den Assertion Error zu verstehen. Nehmen wir an, Sie haben zwei Variablen a und b, die Sie vergleichen müssen. Um zu prüfen, ob a und b gleich sind oder nicht, fügen Sie ein assert-Schlüsselwort davor ein, das eine Assertion-Ausnahme auslöst, wenn der Ausdruck false zurückgibt.

try: a = 100 b = "DataCamp" assert a == bexcept AssertionError: print ("Assertion Exception Raised.")else: print ("Success, no error!")
Assertion Exception Raised.

Attributfehler

Wenn ein nicht vorhandenes Attribut referenziert wird und diese Attributreferenz oder -zuweisung fehlschlägt, wird ein Attributfehler ausgelöst.

Im folgenden Beispiel können Sie beobachten, dass das Klassenobjekt Attributes kein Attribut mit dem Namen attribute hat.

class Attributes(object): a = 2 print (a)try: object = Attributes() print (object.attribute)except AttributeError: print ("Attribute Exception Raised.")
2Attribute Exception Raised.

Import Error

ImportError wird ausgelöst, wenn Sie versuchen, ein Modul zu importieren, das in seinem Standardpfad nicht existiert (nicht geladen werden kann), oder sogar, wenn Sie einen Tippfehler im Namen des Moduls machen.

import nibabel
---------------------------------------------------------------------------ModuleNotFoundError Traceback (most recent call last)<ipython-input-6-9e567e3ae964> in <module>----> 1 import nibabelModuleNotFoundError: No module named 'nibabel'

Lookup Error

Lookup Error dient als Basisklasse für die Ausnahmen, die auftreten, wenn ein Schlüssel oder Index, der in einer Abbildung oder Sequenz einer Liste/eines Wörterbuchs verwendet wird, ungültig ist oder nicht existiert.

Die zwei Arten von Ausnahmen, die ausgelöst werden, sind:

  • IndexError
  • KeyError

Key Error

Wenn ein Schlüssel, auf den Sie versuchen zuzugreifen, nicht im Wörterbuch gefunden wird, wird eine key Fehlerausnahme ausgelöst.

try: a = {1:'a', 2:'b', 3:'c'} print (a) except LookupError: print ("Key Error Exception Raised.")else: print ("Success, no error!")
Key Error Exception Raised.

Indexfehler

Wenn Sie versuchen, auf einen Index (Folge) einer Liste zuzugreifen, der in dieser Liste nicht existiert oder außerhalb des Bereichs dieser Liste liegt, wird ein Indexfehler ausgelöst.

try: a = print (a) except LookupError: print ("Index Error Exception Raised, list index out of range")else: print ("Success, no error!")
Index Error Exception Raised, list index out of range

Speicherfehler

Wie bereits erwähnt, wird ein Speicherfehler ausgelöst, wenn eine Operation nicht genügend Speicher für die weitere Verarbeitung erhält.

Name Error

Name Error wird ausgelöst, wenn ein lokaler oder globaler Name nicht gefunden wird.

Im folgenden Beispiel ist die ans Variable nicht definiert. Daher erhalten Sie ein name error.

try: print (ans)except NameError: print ("NameError: name 'ans' is not defined")else: print ("Success, no error!")
NameError: name 'ans' is not defined

Laufzeitfehler

Nicht implementierter Fehler

Dieser Abschnitt des Tutorials ist von dieser Quelle abgeleitet. Runtime Error dient als Basisklasse für den NotImplemented Error. Abstrakte Methoden in benutzerdefinierten Klassen sollten diese Ausnahme auslösen, wenn die abgeleiteten Klassen die Methode überschreiben.

class BaseClass(object): """Defines the interface""" def __init__(self): super(BaseClass, self).__init__() def do_something(self): """The interface, not implemented""" raise NotImplementedError(self.__class__.__name__ + '.do_something')class SubClass(BaseClass): """Implementes the interface""" def do_something(self): """really does something""" print (self.__class__.__name__ + ' doing something!')SubClass().do_something()BaseClass().do_something()
SubClass doing something!---------------------------------------------------------------------------NotImplementedError Traceback (most recent call last)<ipython-input-1-57792b6bc7e4> in <module> 14 15 SubClass().do_something()---> 16 BaseClass().do_something()<ipython-input-1-57792b6bc7e4> in do_something(self) 5 def do_something(self): 6 """The interface, not implemented"""----> 7 raise NotImplementedError(self.__class__.__name__ + '.do_something') 8 9 class SubClass(BaseClass):NotImplementedError: BaseClass.do_something

Type Error

Die Ausnahme „Type Error“ wird ausgelöst, wenn zwei unterschiedliche oder nicht verwandte Typen von Operanden oder Objekten kombiniert werden.

Im folgenden Beispiel werden ein Integer und ein String addiert, was zu einem typeFehler führt.

try: a = 5 b = "DataCamp" c = a + bexcept TypeError: print ('TypeError Exception Raised')else: print ('Success, no error!')
TypeError Exception Raised

Wertfehler

Der Wertfehler wird ausgelöst, wenn die eingebaute Operation oder eine Funktion ein Argument erhält, das einen korrekten type, aber ungültigen value hat.

Im folgenden Beispiel erhält die eingebaute Operation float ein Argument, das eine Zeichenfolge (Wert) ist, die für den Typ float ungültig ist.

try: print (float('DataCamp'))except ValueError: print ('ValueError: could not convert string to float: \'DataCamp\'')else: print ('Success, no error!')
ValueError: could not convert string to float: 'DataCamp'

Benutzerdefinierte Ausnahmen in Python

Dieser Abschnitt des Tutorials ist von dieser Quelle abgeleitet.

Wie im vorherigen Abschnitt des Tutorials gelernt, hat Python viele eingebaute Ausnahmen, die Sie in Ihrem Programm verwenden können. Dennoch kann es manchmal notwendig sein, eigene Exceptions mit eigenen Meldungen zu erstellen, um Ihren Zweck zu erfüllen.

Das können Sie erreichen, indem Sie eine neue Klasse erstellen, die von der vordefinierten Exception-Klasse in Python abgeleitet wird.

class UnAcceptedValueError(Exception): def __init__(self, data): self.data = data def __str__(self): return repr(self.data)Total_Marks = int(input("Enter Total Marks Scored: "))try: Num_of_Sections = int(input("Enter Num of Sections: ")) if(Num_of_Sections < 1): raise UnAcceptedValueError("Number of Sections can't be less than 1")except UnAcceptedValueError as e: print ("Received error:", e.data)

Enter Total Marks Scored: 10Enter Num of Sections: 0Received error: Number of Sections can't be less than 1

Im obigen Beispiel haben Sie beobachtet, dass bei einer Eingabe kleiner als 1 eine eigene Exception ausgelöst und behandelt wird. Viele Standardmodule definieren ihre Ausnahmen, um Fehler zu melden, die in den von ihnen definierten Funktionen auftreten können.

Nebeneffekte der Python-Ausnahmebehandlung

Die Verwendung der Python-Ausnahmebehandlung hat auch einen Nebeneffekt. So werden Programme, die try-except-Blöcke zur Behandlung von Ausnahmen verwenden, etwas langsamer laufen, und die Größe Ihres Codes wird zunehmen.

Unten ist ein Beispiel, in dem das timeit-Modul von Python verwendet wird, um die Ausführungszeit von 2 verschiedenen Anweisungen zu überprüfen. In stmt1 wird ZeroDivisionError mit try-except behandelt, während in stmt2 die if-Anweisung als normale Prüfbedingung verwendet wird. Dann führen Sie diese Anweisungen 10000 Mal mit der Variablen a=0 aus. Dabei ist zu beachten, dass die Ausführungszeit der beiden Anweisungen unterschiedlich ist. Sie werden feststellen, dass stmt1, das die Exception behandelt, etwas mehr Zeit benötigt als stmt2, das nur den Wert prüft und nichts tut, wenn die Bedingung nicht erfüllt ist.

Daher sollten Sie die Verwendung der Python-Exception-Behandlung einschränken und nur in seltenen Fällen verwenden. Zum Beispiel, wenn Sie nicht sicher sind, ob die Eingabe ein Integer oder ein Float für arithmetische Berechnungen ist, oder wenn Sie nicht sicher sind, ob eine Datei existiert, während Sie versuchen, sie zu öffnen.

import timeitsetup="a=0"stmt1 = '''\try: b=10/aexcept ZeroDivisionError: pass'''
stmt2 = '''\if a!=0: b=10/a'''
print("time=",timeit.timeit(stmt1,setup,number=10000))print("time=",timeit.timeit(stmt2,setup,number=10000))
time= 0.003897680000136461time= 0.0002797570000439009

Glückwunsch zum Abschluss dieses Tutorials.

Wie Sie gelernt haben, hilft die Ausnahmebehandlung dabei, den typischen Kontrollfluss Ihres Programms zu durchbrechen, indem sie einen Mechanismus zur Entkopplung der Python-Fehlerbehandlung bereitstellt und Ihren Code robuster macht.

Die Python-Ausnahmebehandlung ist einer der wichtigsten Faktoren, um Ihren Code produktions- und zukunftssicher zu machen, abgesehen vom Hinzufügen von Unit-Tests und objektorientierter Programmierung.

Es handelt sich um eine mächtige Technik und ist ein Konzept aus nur vier Blöcken. Der try-Block sucht nach Ausnahmen, die vom Code geworfen werden, während der except-Block diese Ausnahmen (eingebaute und benutzerdefinierte) behandelt.

Eine gute Übung für Sie alle wäre, alle vier Komponenten der Ausnahmebehandlung zu verwenden und zu versuchen, Ihren Code robuster zu machen.

Schreibe einen Kommentar

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