Le eccezioni in Python: sollevare e gestire un’eccezione

Le eccezioni in Python: sollevare e gestire un’eccezione

1 Set 2018 5 Di Admin M.

Nel precedente articolo abbiamo introdotto la sintassi, ora è giunto il momento di parlare delle eccezioni in Python.

Negli esempi presentati finora abbiamo già avuto a che fare, anche se in modo superficiale, con le eccezioni (exception) di Python.

 

Il meccanismo delle eccezioni è presente anche in altri linguaggi di programmazione come Java e C++ ed è ampiamente collaudato.

 


Le eccezioni sono eventi scatenati da errori di varia natura.


 

  • Quando prevediamo che in un dato contesto si possa verificare un’eccezione, possiamo scrivere del codice per “gestirla” (in inglese to handle).

   Si parla dunque di handled exception.

 

  • Se invece un’eccezione si verifica in un contesto imprevisto, non viene “gestita” (unhandled exception, eccezione non gestita) e quindi causerà l’uscita dal blocco di codice in cui si presenta.

 

Se però il blocco di codice più esterno ha “previsto” l’eccezione scatenata, potrà occuparsene.

In caso contrario, l’esecuzione uscirà anche da questo blocco e così via: alla fine potrebbe provocare l’uscita dal blocco più esterno, ovvero dal programma stesso.

 

 

Vediamo ora cosa vuol dire gestire e anche “sollevare” (da to raise in inglese) un’eccezione.

 


Potrebbe sembrare assurdo il fatto che sia possibile “sollevare” un’eccezione, visto che il nostro compito dovrebbe essere quello di prevederle.

Uno degli aspetti più interessanti delle eccezioni è proprio questo: la possibilità di sollevare un’eccezione in modo che altre parti del programma la gestiscano.


 

Gestire le eccezioni in Python: istruzioni try ed except 

 

Per imparare a gestire le eccezioni in Python, vediamo come generarne una.

Una tra le eccezioni più semplici da provocare è, senza dubbio, quella generata dalla divisione per zero:

 

Eccezioni in Python - Divisione per zero

 

 

In questo caso, l’eccezione è stata generata in modalità interattiva con IDLE.

Per questo motivo ci siamo trovati di nuovo con il prompt di Python in attesa di ricevere nuovi comandi, come se niente fosse.

 

Vediamo cosa accade invece se generiamo la stessa eccezione in uno script come il seguente, che chiameremo div_by_zero.py:

 

Script eccezione - Python

 

 

L’output di questo script:

 

Output script con eccezione

 

 

Il nostro programma è entrato in crash (in inglese crash significa crollare). Non c’è traccia del nostro messaggio finale.

Proviamo ora a gestire l’eccezione con questa nuova versione dello script div_by_zero2.py: 

 

Script con istruzioni try ed except- Python

 

 

L’output dello script è diverso:

 

Output script con istruzioni try ed except - Python

 

 

Come possiamo notare: invece delle righe incomprensibili (almeno per ora) dell’output precedente, vengono presentate informazioni più chiare e abbiamo anche il messaggio finale del nostro programma.

 


domande

 

  • Osservando la nostra versione dello script può sorgere spontaneamente qualche domanda:

 

 – Cosa sarebbe successo se ci fossero state altre istruzioni tra l’errore e l’except ?

– Se invece non ci fosse stata alcuna eccezione cosa sarebbe accaduto alle istruzioni contenute nell’except ?

– E se poi fosse stata sollevata un’eccezione diversa da ZeroDivisionError ?

 

 

E’ pertanto importante comprendere il funzionamento dell’istruzione composta try…except

 


 

Come funziona l’istruzione try…except?

 

  • Se non viene sollevata alcuna eccezione, il blocco di istruzioni che segue il try viene eseguito fino in fondo. Quindi il controllo passa alle istruzioni che seguono il blocco except, il quale non viene quindi eseguito.

 

  • Al contrario, se all’interno del blocco try  viene sollevata un’eccezione, allora tutte le eventuali istruzioni che seguono quella che ha scatenato l’errore, vengono saltate e il controllo passa immediatamente al blocco except, sempre che questo contenga l’eccezione corretta.

 

  •  Se invece l’except  riguarda un altro tipo di eccezione, viene saltata l’esecuzione dell’intero blocco di istruzioni che contiene il try e il controllo passa al blocco più esterno, che forse offre un except di tipo corretto e in ultima istanza al sistema operativo.

 

  •  E’ ovviamente possibile prevedere più blocchi except per ogni try, ognuno con le istruzioni dedicate a uno o più tipi di eccezioni. L’ultima clausola except può non specificare alcuna eccezione; in questo caso quest’ultima clausola (denominata default except ) individuerà ogni eccezione non gestita precedentemente.

 

 

Vediamo una porzione di codice contenente due except:

 

Script con due except - Python

 

 

Come vediamo, sono previsti due blocchi except per due diversi tipi di eccezioni: TypeError  e NameError.

 

Blocco try contenente due blocchi except - Python

 

 

  • Dagli esempi appena mostrati, notiamo come nel primo caso, dove non viene dichiarato arg, venga eseguito il blocco del secondo except.
  • Nel secondo caso invece, arg viene dichiarato, ma il suo tipo non è accettabile peri l comando dict; pertanto viene eseguito il blocco del primo except.

 

 

Sollevare un’eccezione in Python: il comando raise

 

Il comando raise permette di “sollevare” un’eccezione in Python, oppure, se viene chiamato senza parametri, di passare al controllo di un’eccezione al blocco di istruzioni più esterno.

Ecco un esempio che presenta entrambe le situazioni:

 

Utilizzo del comando raise con e senza parametri

 

 

La prima riga di output è quella che abbiamo gestito direttamente nel corpo del try e la seconda è prodotta dal blocco except. In entrambi i casi viene impiegata l’istruzione print.

 

Quindi, dopo aver eseguito un raise  senza parametri, il controllo è stato restituito all’interprete interattivo, il quale ha visualizzato le ultime righe che contengono il tipo di eccezione oltre al messaggio “Bingo!” che abbiamo chiesto di visualizzare.

 

 

Le istruzioni finally ed else

 

Il blocco try…except  per le eccezioni in Python, prevede la clausola opzionale finally  e, come per il for, anche else.

 

  • Il blocco di istruzioni contenuto in finally  viene eseguito sempre e comunque (finally in inglese significa “alla fine” e non “finalmente”).
  • Quello contenuto in else viene invece eseguito solo se tutto è andato bene e non sono state sollevate eccezioni.

 

Il seguente script di esempio finally-else.py  ci chiarirà le idee meglio di qualsiasi definizione:

 

Istruzioni finally-else

 

 


Le prime tre righe del programma possono non essere del tutto chiare:

la prima importa la libreria sys

la seconda e la terza caricano nelle due variabili nominatore e denominatore i primi due parametri passati a finally-else.py dalla riga di comando.


 

Adesso osserviamo due esecuzioni distinte dello script:

  • nella prima definiremo volutamente un divisore uguale a zero
  • nella seconda forniremo due valori corretti

 

Output script istruzioni finally-else

 

 

Nell’output dello script notiamo che:

  • nel primo caso, dove viene sollevata un’eccezione, viene visualizzato il messaggio d’errore (except) e infine il messaggio di conclusione del programma (finally).
  • nel secondo caso, senza eccezioni, viene visualizzato il messaggio contenente il risultato (else) e infine, nuovamente, il messaggio di conclusione del programma (finally).

 

 

La funzione exc_info

 

Nell’ultimo esempio abbiamo visto come importare la libreria sys e come usare la lista argv che corrisponde all’elenco dei parametri passati dalla riga di comando.

 

Nella libreria sys esiste anche una funzione utilissima che ha a che fare con le eccezioni in Python: exc_info.

Quando ci troviamo a gestire un’eccezione sconosciuta, per esempio con una default except, come possiamo accedere alla descrizione dell’ultima eccezione?

Proprio con exc_info.

 


Un blocco except senza nessun tipo di eccezione indicata è una pratica sconsigliabile:

si corre il rischio di nascondere problemi totalmente imprevisti in fase di programmazione.

E’ sempre meglio specificare le eccezioni in Python per le quali è stato definito un blocco try.


 

Vediamo come usare questa funzione con lo script finally-else2.py:

 

Script funzione exc_info

 

 

Di seguito, l’output dello script:

 

Output script funzione exc_info

 

 

I tre valori della lista sys.exc_info sono rispettivamente:

  • il tipo di eccezione scatenata
  • l’eventuale valore a essa associato (ovvero l’eventuale parametro con cui è inizializzata l’eccezione sollevata da raise )
  • un oggetto traceback.

 


Il traceback è un oggetto avanzato che permette di visualizzare lo stack del programma al momento in cui si è verificata l’eccezione.

In parole povere, l’elenco di script attualmente caricati da Python, a partire da quello più “esterno”.

Nell’esempio precedente, se avessimo visualizzato il traceback con la funzione print_tb dell’omonimo modulo, avremmo ottenuto solo la seguente riga:

File “finally-else2.py”, line 5, in <module>.


 

Py

 

Abbiamo concluso così anche le eccezioni in Python, non ci resta che passare a funzioni,  classi  e input/output.

 

Se hai saltato qualche argomento, niente paura: trovi tutto nella sezione dedicata alla guida alla programmazione con Python!

 

Iscriviti alla nostra newsletter per rimanere aggiornato sui prossimi articoli!