Zoeken…


Invoering

Fouten die tijdens de uitvoering worden gedetecteerd, worden uitzonderingen genoemd en zijn niet onvoorwaardelijk fataal. De meeste uitzonderingen worden niet behandeld door programma's; het is mogelijk om programma's te schrijven die geselecteerde uitzonderingen verwerken. Er zijn specifieke functies in Python voor het omgaan met uitzonderingen en uitzonderingslogica. Bovendien hebben uitzonderingen een rich type-hiërarchie, alle BaseException van het BaseException type.

Syntaxis

  • uitzondering opwerpen
  • raise # een uitzondering opnieuw verhogen die al is opgeworpen
  • verhogen uitzondering van oorzaak # Python 3 - stel de oorzaak van de uitzondering in
  • raise exception from None # Python 3 - onderdruk alle uitzonderingscontext
  • proberen:
  • behalve [uitzonderingstypes] [ als identificatie ] :
  • anders:
  • Tenslotte:

Uitzonderingen opheffen

Als uw code een voorwaarde tegenkomt die niet weet hoe ermee om te gaan, zoals een onjuiste parameter, zou dit de juiste uitzondering moeten opleveren.

def even_the_odds(odds):
    if odds % 2 != 1:
        raise ValueError("Did not get an odd number")
    
    return odds + 1

Uitzonderingen vangen

Gebruik try...except: om uitzonderingen te vangen. U moet een zo nauwkeurig mogelijke uitzondering opgeven:

try:
    x = 5 / 0
except ZeroDivisionError as e:
    # `e` is the exception object
    print("Got a divide by zero! The exception was:", e)
    # handle exceptional case
    x = 0  
finally:
    print "The END"
    # it runs no matter what execute.

De opgegeven uitzonderingsklasse - in dit geval ZeroDivisionError - vangt elke uitzondering op die in die klasse of in een subklasse van die uitzondering valt.

ZeroDivisionError is bijvoorbeeld een subklasse van ArithmeticError :

>>> ZeroDivisionError.__bases__
(<class 'ArithmeticError'>,)

En dus zal het volgende nog steeds de ZeroDivisionError vangen:

try:
    5 / 0
except ArithmeticError:
    print("Got arithmetic error")

Eindelijk de opschoningscode uitvoeren

Soms wilt u dat er iets gebeurt, ongeacht welke uitzondering er ook is gebeurd, bijvoorbeeld als u bepaalde bronnen moet opruimen.

De finally blok van een try clausule zal gebeuren, ongeacht of er uitzonderingen zijn gerezen.

resource = allocate_some_expensive_resource()
try:
    do_stuff(resource)
except SomeException as e:
    log_error(e)
    raise  # re-raise the error
finally:
    free_expensive_resource(resource)

Dit patroon wordt vaak beter afgehandeld met contextmanagers (met behulp van de instructie with ).

Uitzonderingen opnieuw opheffen

Soms wilt u een uitzondering maken om deze te inspecteren, bijvoorbeeld voor logboekdoeleinden. Na de inspectie wilt u dat de uitzondering zich blijft verspreiden zoals voorheen.

Gebruik in dit geval eenvoudig de instructie raise zonder parameters.

try:
    5 / 0
except ZeroDivisionError:
    print("Got an error")
    raise

Houd er echter rekening mee dat iemand verderop in de bellersstapel de uitzondering nog steeds kan opvangen en op de een of andere manier kan verwerken. De uitgevoerde output kan in dit geval hinderlijk zijn omdat het in elk geval zal gebeuren (gevangen of niet gevangen). Het is dus misschien een beter idee om een andere uitzondering te maken, met uw opmerking over de situatie en de oorspronkelijke uitzondering:

try:
    5 / 0
except ZeroDivisionError as e:
    raise ZeroDivisionError("Got an error", e)

Maar dit heeft het nadeel dat het uitzonderingsspoor precies tot deze raise gereduceerd, terwijl de raise zonder argument het oorspronkelijke uitzonderingsspoor behoudt.

In Python 3 kun je de originele stapel behouden door de raise - from syntaxis te gebruiken:

    raise ZeroDivisionError("Got an error") from e

Chain uitzonderingen met raise vanaf

Tijdens het verwerken van een uitzondering wilt u misschien een andere uitzondering opwerpen. Als u bijvoorbeeld een IOError tijdens het lezen van een bestand, wilt u misschien een applicatiespecifieke fout genereren die in plaats daarvan aan de gebruikers van uw bibliotheek wordt gepresenteerd.

Python 3.x 3.0

U kunt uitzonderingen koppelen om aan te geven hoe de verwerking van uitzonderingen is verlopen:

>>> try:
    5 / 0
except ZeroDivisionError as e:
    raise ValueError("Division failed") from e

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
ValueError: Division failed

Uitzonderingshiërarchie

Uitzonderingsafhandeling vindt plaats op basis van een uitzonderingshiërarchie, bepaald door de overervingsstructuur van de uitzonderingsklassen.

IOError en OSError zijn bijvoorbeeld beide subklassen van EnvironmentError . Code die een IOError vangt, zal geen OSError vangen. Code die een EnvironmentError vangt, zal echter zowel IOError s als OSError s vangen.

De hiërarchie van ingebouwde uitzonderingen:

Python 2.x 2.3
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StandardError
      |    +-- BufferError
      |    +-- ArithmeticError
      |    |    +-- FloatingPointError
      |    |    +-- OverflowError
      |    |    +-- ZeroDivisionError
      |    +-- AssertionError
      |    +-- AttributeError
      |    +-- EnvironmentError
      |    |    +-- IOError
      |    |    +-- OSError
      |    |         +-- WindowsError (Windows)
      |    |         +-- VMSError (VMS)
      |    +-- EOFError
      |    +-- ImportError
      |    +-- LookupError
      |    |    +-- IndexError
      |    |    +-- KeyError
      |    +-- MemoryError
      |    +-- NameError
      |    |    +-- UnboundLocalError
      |    +-- ReferenceError
      |    +-- RuntimeError
      |    |    +-- NotImplementedError
      |    +-- SyntaxError
      |    |    +-- IndentationError
      |    |         +-- TabError
      |    +-- SystemError
      |    +-- TypeError
      |    +-- ValueError
      |         +-- UnicodeError
      |              +-- UnicodeDecodeError
      |              +-- UnicodeEncodeError
      |              +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
       +-- ImportWarning
       +-- UnicodeWarning
       +-- BytesWarning
Python 3.x 3.0
BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      +-- 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
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Uitzonderingen zijn ook objecten

Uitzonderingen zijn gewone Python-objecten die erven van de ingebouwde BaseException . Een Python-script kan de instructie raise om de uitvoering te onderbreken, waardoor Python op dat moment een stacktracering van de call-stack en een weergave van de uitzonderingsinstantie afdrukt. Bijvoorbeeld:

>>> def failing_function():
...     raise ValueError('Example error!')
>>> failing_function()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in failing_function
ValueError: Example error!

die zegt dat een ValueError met het bericht 'Example error!' werd opgevoed door onze failing_function() , die werd uitgevoerd in de interpreter.

Oproepcode kan ervoor kiezen om alle soorten uitzonderingen die een oproep kan veroorzaken, te verwerken:

>>> try:
...     failing_function()
... except ValueError:
...     print('Handled the error')
Handled the error

U kunt de uitzonderingsobjecten verkrijgen door ze toe te wijzen in het gedeelte except... van de code voor de afhandeling van uitzonderingen:

>>> try:
...     failing_function()
... except ValueError as e:
...     print('Caught exception', repr(e))
Caught exception ValueError('Example error!',)

Een complete lijst met ingebouwde Python-uitzonderingen, samen met hun beschrijvingen, is te vinden in de Python-documentatie: https://docs.python.org/3.5/library/exceptions.html . En hier is de volledige lijst hiërarchisch gerangschikt: Uitzonderingshiërarchie .

Aangepaste uitzonderingen maken

Maak een klasse die overneemt van Exception :

class FooException(Exception):
    pass
try:
    raise FooException("insert description here")
except FooException:
    print("A FooException was raised.")

of een ander uitzonderingstype:

class NegativeError(ValueError):
      pass

def foo(x):
    # function that only accepts positive values of x
    if x < 0:
        raise NegativeError("Cannot process negative numbers")
    ...  # rest of function body
try:
    result = foo(int(input("Enter a positive integer: ")))  # raw_input in Python 2.x
except NegativeError:
    print("You entered a negative number!")
else:
    print("The result was " + str(result))

Vang niet alles!

Hoewel het vaak verleidelijk is om elke Exception te vangen:

try:
    very_difficult_function()
except Exception:
    # log / try to reconnect / exit gratiously
finally:
    print "The END"
    # it runs no matter what execute.

Of zelfs alles (inclusief BaseException en al zijn kinderen inclusief Exception ):

try:
    even_more_difficult_function()
except:
    pass  # do whatever needed

In de meeste gevallen is het een slechte gewoonte. Het kan meer vangen dan bedoeld, zoals SystemExit , KeyboardInterrupt en MemoryError - die in het algemeen anders moeten worden behandeld dan gebruikelijke systeem- of logische fouten. Het betekent ook dat er geen duidelijk begrip is voor wat de interne code fout kan doen en hoe deze correct kan worden hersteld. Als u elke fout opmerkt, weet u niet welke fout is opgetreden of hoe u deze kunt oplossen.

Dit wordt meestal 'bug maskering' genoemd en moet worden vermeden. Laat uw programma crashen in plaats van stil te mislukken of nog erger, te mislukken op een dieper uitvoeringsniveau. (Stel je voor dat het een transactiesysteem is)

Gewoonlijk worden deze constructies op het uiterste niveau van het programma gebruikt en worden de details van de fout vastgelegd zodat de fout kan worden opgelost of de fout meer specifiek kan worden afgehandeld.

Meerdere uitzonderingen opvangen

Er zijn een paar manieren om meerdere uitzonderingen op te vangen .

De eerste is door een tuple van de uitzonderingen te maken die je op dezelfde manier wilt vangen en verwerken. In dit voorbeeld negeert de code de uitzonderingen van KeyError en AttributeError .

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except (KeyError, AttributeError) as e:
    print("A KeyError or an AttributeError exception has been caught.")

Als u verschillende uitzonderingen op verschillende manieren wilt verwerken, kunt u voor elk type een afzonderlijk uitzonderingsblok opgeven. In dit voorbeeld vangen we nog steeds de KeyError en AttributeError , maar behandelen we de uitzonderingen op verschillende manieren.

try:
    d = {}
    a = d[1]
    b = d.non_existing_field
except KeyError as e:
    print("A KeyError has occurred. Exception message:", e)
except AttributeError as e:
    print("An AttributeError has occurred. Exception message:", e)

Praktische voorbeelden van uitzonderingsbehandeling

Gebruikers invoer

Stel je voor dat een gebruiker een nummer via input . U wilt ervoor zorgen dat de invoer een nummer is. Je kunt try / except dit gebruiken:

Python 3.x 3.0
while True:
    try:
        nb = int(input('Enter a number: '))
        break
    except ValueError:
        print('This is not a number, try again.')

Opmerking: Python 2.x zou in plaats daarvan raw_input gebruiken; de functie- input bestaat in Python 2.x maar heeft verschillende semantiek. In het bovenstaande voorbeeld zou input ook uitdrukkingen zoals 2 + 2 accepteren die tot een getal evalueren.

Als de invoer niet kan worden geconverteerd naar een geheel getal, wordt een ValueError . Je kunt het vangen met except . Als er geen uitzondering wordt verhoogd, break springt uit de lus. Na de lus bevat nb een geheel getal.

Woordenboeken

Stel je voor dat je een lijst met opeenvolgende gehele getallen doorloopt, zoals range(n) , en je hebt een lijst met woordenboeken d die informatie bevat over dingen die je moet doen als je bepaalde bepaalde gehele getallen tegenkomt, zeg de volgende d[i] overslaan .

d = [{7: 3}, {25: 9}, {38: 5}]

for i in range(len(d)):
    do_stuff(i)
    try:
       dic = d[i]
       i += dic[i]
    except KeyError:
       i += 1

Er wordt een KeyError wanneer u probeert een waarde uit een woordenboek te halen voor een sleutel die niet bestaat.

Anders

Code in een ander blok wordt alleen uitgevoerd als er geen uitzonderingen zijn gemaakt door de code in het try blok. Dit is handig als u code hebt die u niet wilt uitvoeren als een uitzondering wordt gegenereerd, maar u niet wilt dat uitzonderingen die door die code worden gegenereerd, worden opgevangen.

Bijvoorbeeld:

try:
    data = {1: 'one', 2: 'two'}
    print(data[1])
except KeyError as e:
    print('key not found')
else:
    raise ValueError()
# Output: one
# Output: ValueError

Merk op dat dit soort else: niet gecombineerd kan worden met een if die de else-clausule start naar een elif . Als u een volgende hebt if het nodig heeft om ingesprongen blijven onder dat else: :

try:
    ...
except ...:
    ...
else:
    if ...:
        ...
    elif ...:
        ...
    else:
        ...


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow