Articles

Uitzondering en Foutafhandeling in Python

Inleiding


Bron

Voordat we ingaan op waarom exception handling essentieel is en de types van ingebouwdein uitzonderingen die Python ondersteunt, is het noodzakelijk om te begrijpen dat er een subtiel verschil is tussen een error en een exception.

Errors kunnen niet worden afgehandeld, terwijl Python exceptions kunnen worden afgehandeld tijdens de run time. Een fout kan een syntax (parsing) fout zijn, terwijl er vele soorten uitzonderingen kunnen zijn die tijdens de uitvoering kunnen voorkomen en niet onvoorwaardelijk onbruikbaar zijn. Een Error kan wijzen op kritieke problemen die een redelijke toepassing niet moet proberen op te vangen, terwijl een Exception kan wijzen op omstandigheden die een toepassing wel moet proberen op te vangen. Fouten zijn een vorm van een ongecontroleerde uitzondering en zijn onherstelbaar zoals een OutOfMemoryError, die een programmeur niet zou moeten proberen op te vangen.

Uitzonderingsafhandeling maakt uw code robuuster en helpt potentiële fouten te voorkomen die uw programma ongecontroleerd zouden doen stoppen. Stel je voor dat je een code hebt geschreven die in productie wordt genomen en toch wordt beëindigd als gevolg van een exception, je klant zou dat niet op prijs stellen, dus het is beter om de betreffende exception van tevoren af te handelen en de chaos te vermijden.

Errors kunnen van verschillende typen zijn:

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

Laten we ze eens een voor een bekijken.

Syntax Error

Syntax errors, ook wel parsing errors genoemd, worden overwegend veroorzaakt wanneer de parser een syntactisch probleem in je code ontdekt.

Laten we een voorbeeld nemen om het te begrijpen.

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

De pijl hierboven geeft aan wanneer de parser op een fout is gestuit tijdens het uitvoeren van de code. Het token dat aan de pijl voorafgaat, veroorzaakt de fout. Om zulke fundamentele fouten te herstellen, zal Python het meeste werk voor u doen, omdat het de bestandsnaam en het regelnummer waarop de fout optrad voor u afdrukt.

Out of Memory Error

Geheugenfouten zijn meestal afhankelijk van het RAM-geheugen van uw systeem en zijn gerelateerd aan Heap. Als u grote objecten in het geheugen heeft (of objecten waarnaar verwezen wordt), dan zult u OutofMemoryError (Bron) zien. Dit kan verschillende oorzaken hebben:

  • Gebruik van een 32-bit Python-architectuur (de maximale geheugentoewijzing is zeer laag, tussen 2GB – 4GB).
  • Laden van een zeer groot gegevensbestand
  • Het draaien van een Machine Learning/Deep Learning-model en nog veel meer.

Je kunt de memory-fout afhandelen met behulp van exception handling, een fallback-exceptie voor wanneer de interpreter helemaal geen geheugen meer heeft en de huidige uitvoering onmiddellijk moet stoppen. In deze zeldzame gevallen roept Python een OutofMemoryError op, waardoor het script op de een of andere manier catch zichzelf en break uit de geheugenfout kan halen en zichzelf kan herstellen.

Hoewel, omdat Python de geheugenbeheer architectuur van de C taal overneemt (malloc() functie), is het niet zeker dat alle processen van het script zich zullen herstellen – in sommige gevallen zal een MemoryError resulteren in een onherstelbare crash. Het is dus geen goede gewoonte om exception handling voor zo’n fout te gebruiken, en het is ook niet aan te raden.

Recursion Error

Het is gerelateerd aan stack en treedt op wanneer je functies aanroept. Zoals de naam al suggereert, recursionfout treedt op wanneer te veel methoden, de een binnen de ander worden uitgevoerd (een met een oneindige recursie), die wordt beperkt door de grootte van de stack.

Al uw lokale variabelen en methoden aanroep geassocieerde gegevens worden geplaatst op de stack. Voor elke methode-aanroep wordt een stack frame gemaakt, en zowel de lokale als de voor de methode-aanroep relevante gegevens worden in dat stack frame geplaatst.

Om deze fout te reproduceren, laten we een functie definiëren recursion die recursief is, wat betekent dat hij zichzelf blijft aanroepen als een oneindige lus method call, je zult StackOverflow of een Recursion Error zien omdat het stack frame voor elke aanroep wordt gevuld met methode data, maar het wordt niet vrijgemaakt.

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

Indentatiefout

Indentatiefout is qua geest vergelijkbaar met de syntaxfout en valt daar ook onder. Het is echter specifiek voor de enige inspringingsgerelateerde problemen in het script.

Dus laten we een snel voorbeeld nemen om een inspringingsfout te begrijpen.

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

Uitzonderingen

Zelfs als de syntaxis van een statement of expressie correct is, kan het toch een fout veroorzaken als het wordt uitgevoerd. Python excepties zijn fouten die worden gedetecteerd tijdens de uitvoering en zijn niet onvoorwaardelijk fataal: je zult snel leren in de tutorial hoe je ze moet behandelen in Python programma’s. Een exception object wordt aangemaakt wanneer een Python script een exception oproept. Als het script de exceptie expliciet niet afhandelt, zal het programma gedwongen worden abrupt te eindigen.

De programma’s handelen uitzonderingen meestal niet af, en resulteren in foutmeldingen zoals hier getoond:

Type Error

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'

Zero Division Error

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

Er zijn verschillende soorten Python exceptions, en het type wordt afgedrukt als onderdeel van het bericht: de types in de twee bovenstaande voorbeelden zijn ZeroDivisionError en TypeError. Beide fout strings worden afgedrukt als de uitzondering type is de naam van de Python’s ingebouwde uitzondering.

Het resterende deel van de fout regel geeft de details van wat de oorzaak van de fout op basis van het type van uitzondering.

Laten we nu eens kijken naar Python’s ingebouwde uitzonderingen.

Ingebouwde uitzonderingen


Bron

Voordat je begint met het leren van de ingebouwde uitzonderingen, laten we nog even snel de vier hoofdcomponenten van exception handling doornemen, zoals in deze figuur te zien is.

  • Probeer: Hiermee wordt het codeblok uitgevoerd waarin u een fout verwacht.
  • Except: Hier definieert u het type uitzondering dat u verwacht in het try-blok (ingebouwd of aangepast).
  • Else: Als er geen uitzondering is, dan wordt dit codeblok uitgevoerd (beschouw dit als een remedie of een terugvaloptie als u verwacht dat een deel van uw script een uitzondering zal opleveren).
  • Ten slotte: Ongeacht of er een uitzondering is of niet, dit blok code zal altijd worden uitgevoerd.

In het volgende deel van de tutorial leert u meer over de veelvoorkomende soorten uitzonderingen en leert u ook hoe u deze kunt afhandelen met behulp van exception handling.

Keyboard Interrupt Error

De KeyboardInterrupt exceptie wordt opgeworpen wanneer u probeert een lopend programma te stoppen door op ctrl+c of ctrl+z in een commandoregel te drukken of de kernel in Jupyter Notebook te onderbreken. Soms is het niet de bedoeling om een programma te onderbreken, maar gebeurt het per ongeluk toch, in welk geval het gebruik van exception handling om dergelijke problemen te voorkomen nuttig kan zijn.

In het onderstaande voorbeeld, als je de cel uitvoert en de kernel onderbreekt, zal het programma een KeyboardInterrupt exception oproepen.inp = input()Laten we nu de KeyboardInterrupt exceptie afhandelen.

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

Standaardfout

Laten we eens wat leren over enkele van de standaardfouten die gewoonlijk kunnen optreden tijdens het programmeren.

Arithmetic Error

  • Zero Division Error
  • OverFlow Error
  • Floating Point Error

Alle bovenstaande excepties vallen onder de Arithmetic basisklasse en worden opgeworpen voor fouten in rekenkundige bewerkingen, zoals hier besproken.

Nul deling

Wanneer de deler (tweede argument van de deling) of de noemer nul is, dan geeft het resultaat een fout bij de nuldeling.

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

OverFlow Error

De Overflow Error treedt op als het resultaat van een rekenkundige bewerking buiten het bereik valt. OverflowError wordt gegenereerd voor gehele getallen die buiten een vereist bereik vallen.

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

Assertion Error

Wanneer een assert statement mislukt, wordt er een Assertion Error gegenereerd.

Laten we een voorbeeld nemen om de assertion error te begrijpen. Stel u heeft twee variabelen a en b, die u moet vergelijken. Om te controleren of a en b gelijk zijn of niet, pas je daarvoor een assert keyword toe, dat een Assertion exceptie zal opwekken wanneer de expressie false zal teruggeven.

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

Attribuutfout

Als naar een niet-bestaand attribuut wordt verwezen, en als die attribuutverwijzing of -toewijzing mislukt, wordt een attribuutfout opgewekt.

In het onderstaande voorbeeld kunt u zien dat het klasse-object Attributes geen attribuut heeft met de naam attribute.

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 wordt opgeworpen wanneer je een module probeert te importeren die niet bestaat (niet kan laden) in zijn standaard pad of zelfs wanneer je een typefout maakt in de naam van de module.

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 fungeert als een basisklasse voor de excepties die optreden wanneer een sleutel of index gebruikt op een mapping of sequence van een lijst/woordenboek ongeldig is of niet bestaat.

De twee soorten excepties die worden opgeworpen zijn:

  • IndexError
  • KeyError

Key Error

Als een sleutel die je probeert te benaderen niet in het woordenboek wordt gevonden, wordt een key fout-exceptie opgeworpen.

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.

Indexfout

Als u toegang probeert te krijgen tot een index (reeks) van een lijst die niet in die lijst bestaat of buiten het bereik van die lijst valt, wordt een indexfout opgeworpen.

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

Geheugenfout

Zoals eerder besproken, wordt een Geheugenfout opgeworpen wanneer een bewerking niet genoeg geheugen krijgt om verder te verwerken.

Naamfout

Naamfout wordt veroorzaakt wanneer een lokale of globale naam niet wordt gevonden.

In het onderstaande voorbeeld is ans variabele niet gedefinieerd. Vandaar dat u een name error krijgt.

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

Runtime Error

Not Implemented Error

Dit deel van de tutorial is afgeleid van deze Bron. Runtime Error fungeert als een basis klasse voor de NotImplemented Error. Abstracte methoden in door gebruikers gedefinieerde klassen moeten deze exceptie oproepen wanneer de afgeleide klassen de methode overriden.

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

Type Error Exception wordt opgeworpen wanneer twee verschillende of niet gerelateerde typen operands of objecten worden gecombineerd.

In het onderstaande voorbeeld worden een integer en een string gecombineerd, wat resulteert in een typefout.

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

Waardefout

Waardefout treedt op als de ingebouwde bewerking of een functie een argument ontvangt dat een correct type maar ongeldig value heeft.

In het onderstaande voorbeeld ontvangt de ingebouwde bewerking float een argument, dat een reeks tekens (waarde) is, die ongeldig is voor een type float.

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'

Python Custom Exceptions

Dit deel van de tutorial is afgeleid van deze Bron.

Zoals in het vorige deel van de tutorial is bestudeerd, heeft Python veel ingebouwde exceptions die je in je programma kunt gebruiken. Toch kan het soms nodig zijn om aangepaste uitzonderingen met aangepaste berichten te maken om uw doel te dienen.

U kunt dit bereiken door een nieuwe klasse te maken, die zal worden afgeleid van de voorgedefinieerde Exception klasse in Python.

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

In het bovenstaande voorbeeld, zoals u hebt opgemerkt dat als u iets minder dan 1 invoert, een aangepaste uitzondering zal worden opgewekt en afgehandeld. Veel standaard modules definiëren hun excepties om fouten te rapporteren die kunnen optreden in functies die zij definiëren.

Verliezen van Python Exception Handling

Het gebruik van Python exception handling heeft ook een neveneffect. Zo zullen programma’s die gebruik maken van try-except blokken om excepties af te handelen iets langzamer lopen, en zal de grootte van je code toenemen.

Hieronder staat een voorbeeld waar de timeit module van Python wordt gebruikt om de uitvoeringstijd van 2 verschillende statements te controleren. In stmt1, wordt try-except gebruikt om ZeroDivisionError af te handelen, terwijl in stmt2if statement wordt gebruikt als een normale controle conditie. Vervolgens voert u deze verklaringen 10000 keer uit met variabele a=0. Het punt om hier op te merken is dat de uitvoeringstijd van beide verklaringen verschillend is. U zult merken dat stmt1, die de uitzondering afhandelt, iets langer duurde dan stmt2, die alleen de waarde controleert en niets doet als niet aan de voorwaarde wordt voldaan.

Hierom moet u het gebruik van Python uitzondering-afhandeling beperken en het alleen gebruiken voor zeldzame gevallen. Bijvoorbeeld wanneer je niet zeker weet of de invoer een integer of een float zal zijn voor rekenkundige berekeningen of wanneer je niet zeker weet of een bestand bestaat terwijl je het probeert te openen.

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

Gefeliciteerd met het voltooien van deze tutorial.

Zoals u hebt geleerd, helpt exceptional handling de typische controlestroom van uw programma te doorbreken door een mechanisme te bieden om Python-foutafhandeling te ontkoppelen en uw code robuuster te maken.

Python exceptional handling is een van de belangrijkste factoren om uw code productieklaar en toekomstbestendig te maken, afgezien van het toevoegen van unit testing en objectgeoriënteerd programmeren.

Het is een krachtige techniek en is een concept van slechts vier blokken. try blok zoekt naar uitzonderingen die door de code worden gegooid, terwijl het except blok deze uitzonderingen afhandelt (ingebouwde en aangepaste).

Een goede oefening voor jullie allemaal zou zijn om alle vier de componenten van exceptionele afhandeling te gebruiken en te proberen je code robuuster te maken.

Geef een reactie

Het e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *