Il momento peggiore per un programmatore è rappresentato dal blocco del programma a causa di un errore.
Esistono due tipi di errori:
Errori sintattici: in questo caso è errato il nome di un comando o di una funzione.
Errori di runtime: in questo caso i nomi sono corretti, ma c'è un errore dovuto al valore assunto da determinate variabili. Esempi di errori di runtime sono i seguenti:
Divisione per zero
lettura di file inesistenti
Quando si ha un errore, il programma si ferma e viene evidenziato un messaggio di errore. Questo evento provoca una brusca interruzione del flusso di controllo del programma, quindi non è più possibile mantenere in vita il programma.
Questo risulta vero per gli errori sintattici, per i quali l'interprete python non sa cosa deve eseguire, ma non è completamente vero per gli errori runtime.
Nel seguente esempio si ha un errore di runtime, in questo caso si dice che è avvenuta una ECCEZIONE, ossia un evento accidentale (in realtà in questo esempio un po' forzato ...).
>>> a, b = 5, 0
>>> print a / b
Traceback (most recent call last):
File "", line 1, in ?
print a / b
ZeroDivisionError: integer division or modulo by zero
È possibile controllare questi eventi accidentali senza terminare il programma, per fare questo si utilizza un costrutto che permette di rilevare le eccezioni e passare il controllo di flusso ad un altro blocco di istruzioni. Tale costrutto è il seguente:
try:
<gruppo di istruzioni sotto test>
except:
<gruppo di istruzioni da eseguire in caso di errore>
else: # opzionale
<gruppo di istruzioni2>
finally: # opzionale, al posto di except
<gruppo di istruzioni3>
Tutte le istruzioni incluse nel blocco try sono tenute sotto controllo durante l'esecuzione del programma. Se tutto va bene il blocco except viene ignorato. In caso contrario, se avviene una eccezione, si salta al blocco di istruzione che seguono la parola except.
Se incapsuliamo ogni operazione a rischio di eccezioni in un blocco try siamo in grado di reagire ad ogni errore runtime senza interrompere il programma.
Tornando all'esempio procedente si può operare in questo modo:
>>> a, b = 5, 0
>>> try:
... print a / b
... except:
... print 'non hai studiato matematica !'
non hai studiato matematica !
È possibile anche gestire tipologie diverse di eccezioni contemporaneamente, ed eseguire blocchi di istruzioni diverse a seconda del tipo di errore.
Per permettere questo è necessario fare seguire alla parola except il nome della classe di errore. Tale nome è rilevabile ad esempio dal messaggio python in caso di eccezione.
Riportando il solito esempio, per gestire in modo più puntuale l'eccezione avremo potuto scrivere nel seguente modo:
>>> a, b = 5, 0
>>> try:
... print a / b
... except ZeroDivisionError:
... print 'non hai studiato matematica, ma con python sei forte !'
non hai studiato matematica, ma con python sei forte !
Nel caso si verificasse una eccezione non legata alla divisione per zero si verificherebbe ugualmente un blocco del programma, anche in presenza del blocco try.
Se si desidera eseguire un particolare gruppo di istruzioni solo nel caso in cui non avvenga nessuna eccezione, basta inserire la parola chiave else, seguito dal blocco di istruzioni desiderate.
Se si desidera far eseguire ugualmente il blocco except anche in caso di nessuna eccezione, è sufficiente sostituire la parola chiave except con la parola chiave finally.
Una nota finale per chi volesse approfondire l'aspetto di gestione delle eccezioni di python. È possibile creare delle classi di eccezioni personalizzate, le quali possono essere generate in un punto qualsiasi utilizzando il comando raise. Ritengo superfluo, ai fini di questo manuale, introdurre ulteriori spiegazioni per questa possibilità di python estremamente avanzata e articolata.