Questo tutorial spiega la gestione delle eccezioni in Python utilizzando il blocco Try Except con l'aiuto di esempi di programmazione:
Due tipi di errore possono causare l'interruzione improvvisa di un programma Python, ad es. Errori di sintassi , e Eccezioni In questa esercitazione, discuteremo il secondo tipo di errore (Eccezioni) con diversi argomenti importanti.
La gestione delle eccezioni nella nostra applicazione sarà molto utile, ad esempio:
- Creare un'applicazione robusta.
- Creare un codice pulito e privo di errori.
Python Prova eccetto
Una buona notizia è che Python ha un buon numero di eccezioni integrate per catturare gli errori nel nostro codice. Inoltre, ci dà l'opportunità di creare eccezioni personalizzate quando nessuna delle eccezioni integrate soddisfa le nostre esigenze.
Che cos'è un'eccezione
In parole povere, ogni volta che l'interprete Python tenta di eseguire codice non valido, solleva un'eccezione e, nei casi in cui tale eccezione non viene gestita, interrompe il normale flusso di istruzioni del programma e stampa un traceback.
Creiamo un codice non valido e vediamo come risponde l'interprete Python.
Aprite una shell Python ed eseguite il seguente codice.
50/0
Questo è uno degli errori più comuni nella programmazione. Il codice qui sopra cerca di dividere il numero 50 da 0 (zero). L'interprete Python vede questa operazione come non valida e solleva un problema di ZeroDivisionError , interrompe il programma e stampa un traceback.
Possiamo vedere chiaramente che ZeroDivisionError è l'eccezione che è stata sollevata. È infatti il modo in cui Python ci dice che non è bello dividere un numero per zero. Anche se in altri linguaggi, come JavaScript, questo non è un errore; e Python proibisce severamente questa pratica.
Inoltre, è importante sapere che questo è solo un oggetto eccezione e che Python ha molti oggetti di questo tipo incorporati. Consultate la documentazione ufficiale di Python per vedere tutte le eccezioni incorporate in Python.
Capire il traceback
Prima di addentrarci nella gestione delle eccezioni, credo sia utile capire cosa succede esattamente se le eccezioni non vengono gestite e come Python fa del suo meglio per informarci dell'errore.
Ogni volta che Python incontra un errore, solleva un'eccezione. Se questa eccezione non viene gestita, produce alcune informazioni chiamate Traceback. Quali informazioni contiene questo traceback?
Contiene:
- Il messaggio di errore indica quale eccezione è stata sollevata e cosa è successo prima che venisse sollevata l'eccezione.
- I vari numeri di riga del codice che ha causato l'errore. Un errore può essere causato da una sequenza di chiamate di funzione chiamata "a stack di chiamata di cui parleremo più avanti.
Anche se è un po' confuso, promettiamo che il prossimo esempio porterà più luce alla nostra comprensione.
Ricordiamo il traceback che è stato stampato dividendo 50 per 0 sopra, possiamo vedere che il traceback contiene le seguenti informazioni:
- File "": indica che il codice è stato eseguito da un terminale di console.
- riga 1: indica che l'errore si è verificato in questo numero di riga.
- ZeroDivisionError: divisione per zero: Ci dice quale eccezione è stata sollevata e cosa l'ha causata.
Proviamo a fare un altro esempio e magari a vedere come una stack di chiamata Aprire un editor, inserire il codice sottostante e salvare con nome tracebackExp .py
def stack1(numb): # 1 div = 0 # 2 stack2(numb, div) # 3 def stack2(numb, div): # 5 compute = numb/div # 6 print(compute) # 7 if __name__ == '__main__': # 9 numb = 5 # 10 stack1(numb) # 11
Aprite un terminale nella directory in cui si trova il file ed eseguitelo.
python tracebackExp.py
Verrà visualizzato il seguente traceback:
Il traceback di cui sopra può sembrare confuso, ma in realtà non lo è. I pythonisti hanno trovato il modo migliore per leggere il traceback, che è dal file dal basso verso l'alto Utilizziamo quindi questa saggezza per cercare di capire cosa ci offre questo traceback.
- In fondo, si trova l'eccezione sollevata e il motivo per cui è stata sollevata.
- Salendo, si ottiene il nome del file tracebackExp .py in cui si è verificato l'errore, il calcolo che ha causato l'errore compute = numb/div, la funzione stack2 e la riga 6 del collegamento in cui è stato eseguito il calcolo.
- Salendo di livello, vediamo che la funzione stack2 è stata chiamata nella funzione stack1 alla riga 3.
- Passando alla parte superiore, vediamo che la funzione stack1 è stata chiamata alla riga 11. < modulo ci dice che è il file che viene eseguito.
Eccezioni comuni di Python
La libreria Python definisce un gran numero di eccezioni integrate. Si può consultare la documentazione di Python o richiamare l'opzione integrata locale () come di seguito:
dir(locals()['__builtins__'])
Non cercheremo di trattare tutte queste eccezioni, ma ne vedremo alcune comuni in cui è probabile imbattersi.
#1) Errore di tipo
Viene sollevato quando un'operazione o una funzione viene applicata a un oggetto di tipo non appropriato.
Esempio 1
Consideriamo il programma seguente, che prende in considerazione un dividendo e un divisore, quindi calcola e stampa il risultato della divisione del dividendo per il divisore.
def compute_division(): dividendo = int(input("Inserisci il dividendo: ")) # cast stringa in int divisore = input("Inserisci il divisore: ") # nessun casting # Calcolo della divisione risultato = dividendo/divisore # stampa risultato print("Il risultato di {}/{} è: {}".format(dividendo, divisore, risultato)) if __name__ == '__main__': risultato = compute_division()
Richiediamo all'utente il valore del dividendo e del divisore, ma dimentichiamo di eseguire il cast del valore stringa del divisore in un numero intero. Quindi, il tipo del dividendo è integer( int ) e il tipo del divisore è string( str ). Otteniamo quindi la Errore di tipo poiché l'operatore di divisione (/) non opera sulle stringhe.
Potrebbe interessarvi sapere che, a differenza di Python, Javascript ha la coercizione di tipo che converte fondamentalmente uno dei tipi di operando in un valore equivalente del tipo dell'altro operando quando gli operandi sono di tipo diverso.
#2) ValoreErrore
Si verifica quando un'operazione o una funzione riceve un argomento di tipo corretto ma con un valore non appropriato.
Esempio 2
Considerate il nostro programma in Esempio 1 sopra.
Se l'utente inserisce un valore alfanumerico per il dividendo, come '3a', il nostro programma solleverà l'eccezione ValueError. Questo perché, sebbene il metodo Python int() accetti qualsiasi numero o stringa e restituisca un oggetto intero, il valore della stringa non deve contenere lettere o qualsiasi altro valore non numerico.
#3) Errore di attributo
Questa eccezione viene sollevata durante l'assegnazione o il riferimento a un attributo che non esiste.
Esempio 3
Si consideri il programma seguente, che prende un numero e ne calcola la radice quadrata utilizzando il modulo matematico di Python.
import math # importare la libreria matematica per avere accesso al suo codice def compute_square_root(number): # calcolare la radice quadrata usando la libreria matematica result = math.sqr(number) return result if __name__ == '__main__': # ottenere dall'utente l'input per il calcolo number = int(input("Compute Square root of: ")) # chiamare la funzione per calcolare la radice quadrata
Quando l'utente inserisce un numero, il nostro programma cerca di utilizzare una funzione del modulo matematico per calcolarne la radice quadrata, ma in questo caso abbiamo commesso un errore: invece di sqrt, abbiamo erroneamente digitato sqr, che non esiste nel modulo matematico.
Quindi, stavamo cercando di fare riferimento a un attributo sqr che non esiste e che ha portato a sollevare l'eccezione AttributeError. Molti di noi commettono spesso questo tipo di errore, quindi non siete soli.
Gestione delle eccezioni con Try Except
Come programmatori, una cosa a cui la maggior parte di noi dedica il proprio tempo è la scrittura di un codice robusto e resistente, che non si rompa a causa di alcuni errori. In Python, possiamo ottenere questo risultato racchiudendo le nostre istruzioni all'interno di un file provare - tranne dichiarazione.
Dichiarazione Try-Except di Python
L'istruzione try-except ha la seguente struttura:
try: #il tuo codice va qui except """Specificare il tipo di eccezione qui""": #gestire l'eccezione qui
Racchiudiamo il codice in tracebackExp .py all'interno di una dichiarazione try-except.
def stack1(numb): # 1 div = 0 # 2 stack2(numb, div) # 3 def stack2(numb, div): # 5 try: # 6 compute = numb/div # 7 print(compute) # 8 except ZeroDivisionError as zde: # 9 print(zde) # 10 if __name__ == '__main__': # 12 numb = 5 # 13 stack1(numb) # 14 print("programma continuo") # 15
L'esecuzione di questo codice produrrà l'output
Ecco come funziona l'istruzione try-except. Python esegue il codice nel blocco try riga 7-8 Se non viene trovato alcun codice non valido, il codice nel blocco except viene considerato come un codice non valido. linea 10 viene saltato e l'esecuzione continua.
Ma se viene trovato un codice non valido, l'esecuzione si ferma immediatamente nel blocco try e controlla se l'eccezione sollevata corrisponde a quella fornita nell'istruzione except linea 9 Se corrisponde, il blocco except viene eseguito e continua. Se non corrisponde, il programma si interrompe.
Il blocco try di solito contiene il codice che può sollevare un'eccezione, mentre il blocco except cattura e gestisce l'eccezione.
Gestione di eccezioni multiple con Except
È possibile gestire più eccezioni con un singolo "except" o con più "except". Tutto dipende da come si vuole gestire ogni eccezione.
#1) Gestire più eccezioni con una singola eccezione
try: #il vostro codice va qui except(Exception1[, Exception2[,...ExceptionN]]): #gestisce l'eccezione qui
Questo metodo viene utilizzato quando si sospetta che il nostro codice possa sollevare diverse eccezioni e si vuole intraprendere la stessa azione in ogni caso. Quindi, se l'interprete Python trova una corrispondenza, verrà eseguito il codice scritto nel blocco except.
Consideriamo l'esempio di codice Python che segue
def get_fraction(valore, idx): arr = [4,5,2,0] # una lista di numeri idx_value = arr[idx] # se idx è> lunghezza di arr, verrà sollevato un IndexError value/idx_value # se idx_value == 0, verrà sollevato un ZeroDivisionError if __name__ =='__main__': # imposta 'valore' e 'idx' value = 54 idx = 3 # chiama la funzione in una dichiarazione try-except. try: result = get_fraction(valore, idx) print("La frazione è ", result) except(IndexError, ZeroDivisionError) come ex: print(ex)
Ci sono due possibili eccezioni che potrebbero essere sollevate in questo caso, ZeroDivisionError e Errore di indice Se viene sollevata una di queste eccezioni, viene eseguito il blocco except.
Nel codice precedente, idx=3, quindi idx_ valore diventa 0 e valore /idx_ valore solleverà ZeroDivisionError
#2) Gestire le eccezioni multiple con le eccezioni multiple
try: #il tuo codice va qui except Exception1: #handle exception1 here except Exception2: #handle exception2 here except ExceptionN: #handle exceptionN here
Se si vuole gestire ogni eccezione separatamente, si può fare in questo modo.
Si consideri l'esempio di codice Python riportato di seguito
def get_fraction(valore, idx): arr = [4,5,2,0] # una lista di numeri idx_value = arr[idx] # se idx è> lunghezza di arr, verrà sollevato un IndexError value/idx_value # se idx_value == 0, verrà sollevato un ZeroDivisionError if __name__ =='__main__': # imposta 'valore' e 'idx' value = 54 idx = 5 # chiama la funzione in una dichiarazione try-excepts. try: result = get_fraction(valore, idx) print("La frazione è ", result) exceptIndexError: print("idx di {} è fuori dall'intervallo".format(idx)) except ZeroDivisionError: print("arr[{}] è 0. Quindi, non può essere diviso per zero".format(idx)) except Exception as ex: print(ex) print("Non sono sicuro di cosa sia successo quindi non è sicuro continuare, \ l'applicazione verrà interrotta") raise ex
Notiamo che Exception è stato usato nell'ultima istruzione except. Questo perché l'oggetto Exception corrisponde a qualsiasi eccezione. Per questo motivo, dovrebbe essere sempre l'ultimo, poiché Python smetterà di controllare gli altri gestori di eccezioni una volta che uno corrisponde.
Nel codice sopra riportato, idx=5 , quindi arr[idx] aumenterà Errore di indice perché idx è maggiore della lunghezza dell'elenco arr
Inoltre, non essendo sicuri di quale eccezione sia stata sollevata dall'applicazione, non è mai sicuro continuare l'esecuzione. Ecco perché abbiamo il tipo Exception per catturare qualsiasi eccezione non prevista. Quindi, informiamo l'utente e interrompiamo l'applicazione sollevando la stessa eccezione.
Dichiarazione Try Else
Questo è un caratteristica opzionale di gestione delle eccezioni e consente di aggiungere codice da eseguire in assenza di errori. Se si verifica un errore, questo blocco else non verrà eseguito.
Consideriamo l'esempio di codice Python qui sotto, apriamo il nostro editor e salviamo il codice come elseTry.py
def fraction_of_one(divisor): value = 1/divisor # se il divisore è zero, verrà sollevato ZeroDivisionError return value if __name__ == '__main__': while True: try: # Riceve l'input dall'utente # se l'input non è un argomento valido per int(), verrà sollevato ValueError divisor = int(input("Inserisci un divisore: ")) # chiama la nostra funzione per calcolare la frazione value = fraction_of_one(divisor) except (ValueError,ZeroDivisionError): print("L'input non può essere zero e deve essere un letterale valido per int(). Per favore, riprova!") else: print("Valore: ", valore) break
Riceviamo un input dall'utente e lo usiamo per dividere 1. Abbiamo due possibili eccezioni, un input utente non valido che causerà ValoreErrore e un zero(0) che causerà ZeroDivisionError La nostra istruzione except gestisce questi errori.
Ora, vogliamo stampare il valore di valore Il nostro blocco else si assicura che venga stampato solo se il blocco try viene eseguito senza errori. Questo è importante perché se si verifica un errore nel blocco try, il file valore sarà indefinito, quindi accedervi darà un altro errore.
Eseguire il codice precedente con Python elseTry.py
L'output qui sopra mostra che per il primo input abbiamo digitato 0 e premere INVIO. Poiché il nostro divisore ha ricevuto 0, 1/divisore ha sollevato zeroDivisionError Il nostro secondo input era k che non è valido per int (), da cui l'eccezione ValoreErrore viene sollevato.
Ma il nostro ultimo input è stato 9, che è valido, e di conseguenza abbiamo ottenuto il valore di " valore " stampato come 0,1111111111111111111111
Prova infine a dichiarare
Questo è anche un caratteristica opzionale di gestione delle eccezioni e verrà sempre eseguito, indipendentemente da ciò che accade nei gestori delle eccezioni.
Cioè:
- Se si verifica o meno un'eccezione
- Anche se negli altri blocchi viene richiamato un "ritorno".
- Anche se lo script viene abbandonato negli altri blocchi
Quindi, se abbiamo un codice che vogliamo eseguire in tutte le situazioni, il blocco finally è il nostro uomo. Questo blocco è usato soprattutto per le operazioni di pulizia, come la chiusura dei file.
Si consideri l'esempio di codice Python riportato di seguito
def readFile(file_path): try: openFile = open(file_path,'r') # Aprire un file in sola lettura print(openFile.readline()) # Leggere la prima riga del contenuto del file except FileNotFoundError as ex: print(ex) finally: print("Pulizia...") openFile.close() if __name__ == '__main__': filePath = './text.txt' readFile(filePath)
Questo codice cerca di aprire e leggere il file text.txt nella sua directory corrente. Se il file esiste, il nostro programma stamperà la prima riga del file, quindi il blocco finally verrà eseguito e chiuderà il file.
Supponiamo di avere un file chiamato text.txt nella directory in cui si trova questo programma e contenente Hello. Se eseguiamo il programma, avremo l'output
Questo esempio è stato scelto intenzionalmente perché volevo che si affrontasse un piccolo problema che può verificarsi quando si chiudono i file nel blocco finally.
Se il file non esiste, l'eccezione FileNotFoundError verrà sollevato e la variabile aprireFile non sarà definito e non sarà un oggetto file. Di conseguenza, il tentativo di chiuderlo nel blocco finally solleverà un'eccezione Errore locale non legato che è una sottoclasse di NomeErrore .
In pratica dice che si sta cercando di fare riferimento alla variabile aprireFile prima che sia stato assegnato.
Un piccolo trucco consiste nell'utilizzare i gestori di eccezioni all'interno del blocco finally.
def readFile(file_path): try: openFile = open(file_path,'r') # Aprire un file in sola lettura print(openFile.readline()) # Leggere la prima riga del contenuto del file except FileNotFoundError as ex: print(ex) finally: try: print("Cleaning...") openFile.close() except: # cattura tutte le eccezioni pass # Ignorare questo errore perché non ci interessa. if __name__ == '__main__': filePath = './text.txt' readFile(filePath)
Se il nostro blocco try solleva FileNotFoundError, avremo il seguente output
Sollevare l'eccezione
Una buona notizia delle eccezioni di Python è che possiamo sollevarle intenzionalmente. Le eccezioni vengono sollevate con l'opzione dichiarazione di aumento .
L'istruzione raise ha la seguente sintassi:
raise [ExceptionName[(*args: Object)]]
Aprire un terminale e sollevare un qualsiasi oggetto di eccezione dalle Eccezioni di Python. Ad esempio, se si solleva ZeroDivisionError:
raise ZeroDivisionError("Impossibile dividere per zero")
Otterremo il traceback:
Allora, perché è importante sollevare eccezioni?
- Quando si lavora con eccezioni personalizzate.
- Durante i controlli di sanità mentale.
Classi di eccezioni personalizzate
Un'eccezione personalizzata è quella che si crea per gestire errori specifici per le proprie esigenze. Il trucco è definire una classe che derivi dall'oggetto Eccezione poi usiamo l'istruzione raise per sollevare la nostra classe di eccezione.
Supponiamo di voler controllare l'input dell'utente e di assicurarci che il valore inserito non sia negativo (sanity check). Naturalmente, potremmo sollevare l'eccezione Python ValueError, ma vorremmo personalizzare l'errore dandogli un nome specifico e autoesplicativo, come ad esempio InputIsNegativeError Ma questa eccezione non è un'eccezione integrata in Python.
Per prima cosa, creiamo la nostra classe base, che deriverà da Exception.
class CustomError(Exception): "Eccezione della classe base per tutte le eccezioni di questo modulo" pass
Quindi creiamo la nostra classe di eccezione, che erediterà la classe base e gestirà il nostro errore specifico.
class InputIsNegativeError(CustomError): """Sollevato quando l'utente inserisce un valore negativo"" pass
Verifichiamo questo
try: value = int(input()) if value <0: raise InputIsNegativeError # Solleva un'eccezione se il valore è negativo except InputIsNegativeError: # cattura e gestisce l'eccezione print("Il valore di input non dovrebbe essere negativo")
Il codice precedente richiede l'input dell'utente e controlla se è negativo. Se è vero, solleva la nostra eccezione personalizzata InputIsNegativeError, che viene poi catturata nella dichiarazione except.
Di seguito è riportato il codice completo:
class CustomError(Exception): "Eccezione della classe base per tutte le eccezioni di questo modulo" pass class InputIsNegativeError(CustomError): """Sollevato quando l'utente inserisce un valore negativo""" pass if __name__ == '__main__': try: value = int(input("Inserisci un numero: ")) if value <0: raise InputIsNegativeError # Solleva l'eccezione se il valore è negativo except InputIsNegativeError: # catch e gestisce l'eccezioneprint("Il valore di ingresso non dovrebbe essere negativo")
Se il valore di ingresso è un numero negativo come -1, si avrà l'uscita:
Per maggiori dettagli sulle eccezioni personalizzate di Python, consultare il documento Python.
Domande frequenti
D #1) In che modo Python gestisce un'eccezione?
Risposta: Python gestisce le eccezioni utilizzando l'opzione dichiarazione try-except Il codice che può sollevare un'eccezione viene inserito ed eseguito nel file provare a bloccare mentre il tranne il blocco contiene il codice che gestirà le eventuali eccezioni.
D #2) Cosa significa sollevare un'eccezione in Python?
Risposta: Ogni volta che l'interprete Python incontra un codice non valido, solleva un'eccezione, che è il modo in cui Python ci dice che è successo qualcosa di inaspettato. Possiamo anche sollevare intenzionalmente delle eccezioni usando l'opzione dichiarazione di aumento .
D #3) Come gestisce Python le eccezioni multiple?
Risposta: Python gestisce le eccezioni multiple utilizzando un singolo blocco except o più blocchi except.
Per un singolo blocco, le eccezioni vengono passate come una tupla: tranne (Eccezione1, Eccezione2,...,EccezioneN) e Python verifica la corrispondenza da destra a sinistra. In questo caso, viene eseguita la stessa azione per ogni eccezione.
Un altro modo per catturare tutte le eccezioni è quello di omettere il nome dell'eccezione dopo la parola chiave except.
except: # gestisce tutte le eccezioni qui
Il secondo modo consiste nell'utilizzare un blocco except per ogni eccezione:
except Exception1: # il codice per gestire Exception1 va qui except Exception2: # il codice per gestire Exception2 va qui except ExceptionN: # il codice per gestire ExceptionN va qui
In questo modo, è possibile intraprendere azioni separate per ciascuna Eccezione.
D #4) Perché la gestione delle eccezioni è importante in Python?
Risposta: Il vantaggio di gestire le eccezioni in Python è che possiamo creare applicazioni robuste, pulite e prive di errori. Non vogliamo che il nostro codice di produzione si blocchi a causa di alcuni errori, quindi gestiamo gli errori e manteniamo la nostra applicazione attiva e funzionante.
D #5) Come si ignora un'eccezione in Python?
Risposta: Per ignorare un'eccezione in Python, utilizzare l'opzione passaggio nel blocco except. Supponiamo di voler ignorare l'eccezione ValueError e lo faremo in questo modo:
tranne ValueError: pass
A meno che non si sappia cosa si sta facendo, è una cattiva pratica ignorare le eccezioni. Almeno, informare l'utente di tutti i potenziali errori.
Conclusione
In questo tutorial, abbiamo trattato: Eccezioni Python, Traceback; come gestire le eccezioni con Prova / Tranne / Altro / Infine blocchi, come Aumentare e infine come creare le nostre eccezioni personalizzate.
Grazie per aver letto!