Introduzione
Quando si parla di gestione delle eccezioni in Python, molti tutorial si fermano al classico try/except. Ma in un progetto reale il problema non è solo “intercettare un errore”: spesso bisogna distinguere tra eccezioni diverse, reagire in modo specifico e mantenere il codice leggibile.
Un sotto-argomento molto utile, pratico e spesso sottovalutato è proprio questo: come gestire più eccezioni in modo ordinato, evitando blocchi ripetitivi e comportamenti ambigui. È una competenza importante quando lavori con input utente, file, API, database o conversioni di dati.
Immagina un programma che legge un numero da tastiera, lo converte e poi lo usa per calcolare un risultato. Potresti incontrare:
- ValueError, se l’input non è convertibile in intero;
- ZeroDivisionError, se usi quel valore come divisore;
- TypeError, se ricevi un tipo inatteso;
- altre eccezioni che è meglio non nascondere accidentalmente.
In questo tutorial vedremo come gestire questi casi con un approccio pulito, scalabile e adatto a codice professionale.
Codice completo
def calcola_prezzo_unitario(spesa_totale, numero_persone):
"""
Calcola quanto deve pagare ciascuna persona.
Gestisce input non validi e divisione per zero.
"""
try:
# Conversione esplicita: se l´input è una stringa non numerica,
# qui può nascere ValueError.
spesa_totale = float(spesa_totale)
numero_persone = int(numero_persone)
# Se numero_persone è 0, scatta ZeroDivisionError.
quota = spesa_totale / numero_persone
return quota
except ValueError as errore:
print(f"Errore di conversione dei dati: {errore}")
return None
except ZeroDivisionError:
print("Non è possibile dividere per zero: il numero di persone deve essere maggiore di 0.")
return None
def leggi_dati_da_utente():
"""
Esempio pratico: acquisizione dati e gestione centralizzata degli errori.
"""
try:
spesa = input("Inserisci la spesa totale: ")
persone = input("Inserisci il numero di persone: ")
quota = calcola_prezzo_unitario(spesa, persone)
if quota is not None:
print(f"Ogni persona deve pagare: {quota:.2f} euro")
except KeyboardInterrupt:
# Gestione di un´interruzione volontaria dell´utente
print("nOperazione annullata dall´utente.")
def analizza_lista_valori(valori):
"""
Mostra come gestire eccezioni diverse in un ciclo,
evitando che un elemento errato blocchi tutto il processo.
"""
risultati = []
for valore in valori:
try:
numero = int(valore)
risultati.append(100 / numero)
except ValueError:
print(f"Valore non convertibile: {valore!r}")
except ZeroDivisionError:
print(f"Divisione impossibile con il valore: {valore!r}")
return risultati
if __name__ == "__main__":
leggi_dati_da_utente()
dati = ["10", "5", "0", "abc", "2"]
output = analizza_lista_valori(dati)
print("Risultati validi:", output) Spiegazione
Nel primo esempio, la funzione calcola_prezzo_unitario mostra un caso molto comune: ricevere dati esterni e convertirli in tipi numerici. Questo passaggio è delicato perché l’input dell’utente è sempre una stringa. Se la stringa non rappresenta un numero valido, float() o int() generano un ValueError.
Gestire ValueError in modo esplicito è utile perché il messaggio restituito all’utente diventa chiaro e mirato. Invece di un crash generico, il programma spiega cosa non va.
Subito dopo gestiamo ZeroDivisionError. È importante separare le eccezioni perché non tutte hanno la stessa causa. Un errore di conversione non va trattato come una divisione per zero: sono problemi diversi e richiedono messaggi diversi.
Nel secondo esempio, analizza_lista_valori, c’è una strategia molto pratica: gestire l’errore per singolo elemento dentro un ciclo. In questo modo, se un valore è errato, il programma non si interrompe; continua a elaborare gli altri elementi.
Questo approccio è particolarmente utile quando lavori con:
- file CSV con righe parzialmente sporche;
- liste di dati provenienti da API esterne;
- input inseriti da utenti diversi;
- processi batch su grandi quantità di record.
Notare anche la gestione di KeyboardInterrupt nel wrapper leggi_dati_da_utente. È una buona pratica intercettare l’interruzione manuale dell’utente quando l’applicazione è interattiva, così il programma termina in modo controllato.
Un aspetto importante: il blocco except deve essere preciso. Evita di scrivere un generico except Exception se non hai un motivo forte. Un gestore troppo ampio rischia di nascondere bug reali, rendendo il debug molto più difficile.
Best practice
- Intercetta solo le eccezioni che sai gestire: se non puoi recuperare dall’errore, spesso è meglio lasciarlo emergere.
- Usa più blocchi except separati quando il trattamento cambia in base al tipo di errore.
- Evita except generici salvo casi ben motivati, ad esempio per logging finale o per un livello applicativo molto alto.
- Non usare le eccezioni per il normale flusso logico: devono rappresentare condizioni anomale, non una scorciatoia.
- Scrivi messaggi chiari per l’utente o per i log, così il problema si diagnostica più facilmente.
- Gestisci gli errori vicino al punto in cui puoi davvero reagire: non sempre conviene catturare tutto nel livello più alto dell’applicazione.
- Nei cicli, valuta l’isolamento dell’errore per elemento se vuoi continuare l’elaborazione dei dati validi.
Un errore comune è questo:
try:
# codice
except:
print("Errore") Questo approccio è troppo vago. Cattura anche eccezioni non previste e può nascondere problemi seri. Meglio scrivere in modo esplicito:
try:
# codice
except ValueError:
print("Dato non valido")
except ZeroDivisionError:
print("Divisione per zero") Se stai costruendo una libreria, inoltre, conviene lasciare che alcune eccezioni native di Python si propaghino: chi usa la tua libreria potrà decidere come trattarle nel proprio contesto.
Riepilogo
Gestire più eccezioni in modo pulito è una competenza fondamentale per scrivere codice Python robusto. In questo tutorial hai visto come:
- intercettare eccezioni diverse con blocchi except separati;
- reagire in modo specifico a errori di conversione e divisione;
- mantenere il programma attivo anche quando un elemento della lista è errato;
- trattare l’interruzione dell’utente in modo ordinato.
Il principio chiave è semplice: non limitarti a “catturare l’errore”, ma gestiscilo in modo intenzionale. Più il tuo codice cresce, più questa disciplina diventa importante per evitare bug nascosti e comportamenti imprevedibili.
Approfondisci con risorse ufficiali
- Documentazione Python — Errors and Exceptions: la guida ufficiale alla gestione delle eccezioni in Python.
- Documentazione Python — Built-in Exceptions: elenco e descrizione delle eccezioni integrate.
- PEP 8: linee guida di stile Python, utili anche per scrivere blocchi try/except leggibili.
- Documentazione Python — input(): utile per capire come gestire correttamente l’input interattivo.
Se vuoi fare un passo in più, prova a riscrivere l’esempio usando logging al posto di print, oppure a trasformare la gestione degli errori in una piccola utility riutilizzabile in più funzioni.
