Vai al contenuto principale

Tutorial Python try-except: best practice ed esempi reali

Impara try-except in Python con esempi reali, best practice ed errori comuni. Scrivi codice per la gestione degli errori più pulito e affidabile.
Aggiornato 3 giu 2026  · 10 min leggi

Quando il codice Python incontra problemi a runtime, spesso solleva un'eccezione. Se non gestite, le eccezioni faranno crashare il tuo programma. Tuttavia, con i blocchi try-except puoi intercettarle, recuperare in modo elegante e mantenere l'applicazione in esecuzione.

Questo tutorial non tratta le basi delle eccezioni: ne parliamo già nella nostra guida alla gestione di eccezioni ed errori in Python. Qui invece approfondiremo l'uso pratico di try-except: come strutturare i blocchi, evitare errori comuni e applicare best practice che rendono il tuo codice più affidabile in scenari reali.

Alla fine, capirai non solo come funziona try-except, ma anche come usarlo in modo pitonico: scrivendo codice di gestione degli errori chiaro, manutenibile e pronto per la produzione.

Se stai ancora imparando Python, ti consiglio di dare un'occhiata al percorso di competenze Python Programming Fundamentals, che ti aiuterà a costruire tutte le competenze essenziali. 

Perché concentrarsi su try-except?

La gestione degli errori in Python riguarda fondamentalmente il progettare programmi in grado di gestire l'imprevisto. E anche se ci sono molti strumenti per gestire gli errori, try-except è la spina dorsale dell'approccio di Python.

Perché è così importante?

  • Rispecchia la filosofia di Python. In Python, lo stile comune è EAFP; Easier to Ask Forgiveness than Permission. Invece di controllare tutto in anticipo (questo file esiste? questo input è valido? il server è disponibile?), provi direttamente l'operazione. Se fallisce, intercetti l'eccezione e la gestisci. Questo porta a codice più corto e pulito.
  • Mantiene il codice in esecuzione in ambienti reali. L'input degli utenti sarà disordinato, i file spariranno, le API falliranno e le reti cadranno. Con try-except puoi scrivere codice che non crolla al primo problema ma reagisce in modo intelligente.
  • È abbastanza flessibile per principianti e professionisti. Un principiante potrebbe usare try-except per intercettare un ValueError durante la conversione dell'input in intero. Un sistema in produzione potrebbe usarlo per registrare errori, ritentare operazioni fallite o sollevare eccezioni personalizzate che rendono il debug più semplice.

Ecco perché questo articolo si concentra su try-except. Padroneggiarlo fa la differenza tra scrivere script che funzionano solo in condizioni perfette e scrivere software robusto, manutenibile e pronto per la produzione.

Anatomia di un blocco Try‑Except

Nel modo più semplice:

try:
    risky_thing()
except SomeError:
    handle_it()

Quando Python incontra un errore dentro il blocco try, passa al blocco except corrispondente invece di far crashare il programma.

Puoi anche estendere questo schema con le clausole else e finally:

try:
    do_something()
except ValueError:
    print("Bad value!")
else:
    print("All good.")
finally:
    clean_up()

Ecco un esempio base funzionante:

try:
    x = int(input("Enter a number: "))
except ValueError:
    print("That wasn’t a number.")
else:
    print("You entered", x)
finally:
    print("Done.")

L'except gestisce l'errore, else viene eseguito solo se tutto è andato bene e finally viene sempre eseguito, anche se premi Ctrl‑C o esci.

Puoi padroneggiare le basi della gestione dell'input utente in Python, dai prompt di base alla validazione avanzata e alle tecniche di gestione degli errori, con il nostro tutorial Python User Input: Handling, Validation, and Best Practices

Gestire più eccezioni

A volte un solo except non basta. Percorsi di codice diversi possono fallire in modi diversi, e catturare tutto e il contrario di tutto con un except senza specifica non è proprio utile; può nascondere bug e rendere il debug un incubo.

Metti che tu stia provando a convertire qualcosa in intero e poi a dividerlo. Ecco cosa non fare:

try:
    result = int(user_input) / 2
except:
    print("Something went wrong.")

Questo cattura tutto, incluse cose che probabilmente non volevi nascondere, come refusi nei nomi delle variabili o eccezioni inaspettate che indicano problemi reali.

Invece, sii specifico:

try:
    result = int(user_input) / 2
except ValueError:
    print("That wasn't a number.")
except ZeroDivisionError:
    print("Division by zero?")

Se hai diversi tipi di eccezioni da trattare allo stesso modo, puoi raggrupparli così:

try:
    result = some_function()
except (TypeError, ValueError):
    print("Something was wrong with the data.")

In questo modo rimani chiaro su cosa potrebbe andare storto, senza duplicare lo stesso blocco più e più volte.

E poi c'è except Exception, che è meglio di un except nudo, ma è ancora troppo ampio. È meglio mirare agli errori specifici che ti aspetti.

Usare i blocchi else e finally

Quando il codice dentro il blocco try ha successo e non vengono sollevate eccezioni, Python esegue il blocco else

try:
    user_id = get_user_id()
except LookupError:
    print("User not found.")
else:
    print("Welcome, user", user_id)

Questo ti aiuta a separare la logica di gestione delle eccezioni dal percorso felice, rendendo il codice più leggibile.

Poi c'è finally. Non gli importa cosa sia successo; viene eseguito comunque. Eccezione? Esegue comunque. Nessuna eccezione? Esegue comunque. Il programma viene interrotto con Ctrl‑C? Esegue comunque. Ottimo per le operazioni di pulizia:

try:
    f = open("data.txt")
    process(f)
except IOError:
    print("Couldn’t open file.")
finally:
    f.close()

Ricorda solo che, se il file non è stato aperto, f potrebbe non esistere nemmeno, quindi fai attenzione. Quando lavori con i file puoi usare il context manager di Python (with open(...) as f:) al suo posto. È più sicuro.

Se vuoi imparare tecniche chiave, come la gestione delle eccezioni e la prevenzione degli errori, per gestire efficacemente l'eccezione KeyError in Python, ti consiglio il nostro tutorial Python KeyError Exceptions and How to Fix Them

Best practice ed errori comuni con Python try-except

Diciamolo: scrivere blocchi try‑except è un po' un'arte. Se fatti bene, impediscono al programma di crashare. Se fatti male, seppelliscono i bug così in profondità che non te ne accorgerai finché la tua app non va giù e gli utenti si lamentano.

Ecco alcune buone abitudini da costruire:

Mantieni i blocchi try stretti. Non racchiudere cento righe di codice in un unico try. Rende solo più difficile capire cosa ha causato il problema. Invece, includi solo il codice che potrebbe fallire:

# Good
try:
    value = int(data)
except ValueError:
    print("Couldn’t convert.")

# Bad
try:
    # Tons of unrelated logic
    value = int(data)
    do_more()
    something_else()
except ValueError:
    print("Huh?")

Evita di controllare le condizioni prima di eseguire l'azione se è più semplice provare e catturare l'errore. Python ha un nome per questo: EAFP, Easier to Ask Forgiveness than Permission. Se stai controllando se un file esiste e poi lo apri, stai creando una race condition. Invece:

try:
    with open("file.txt") as f:
        content = f.read()
except FileNotFoundError:
    print("No file.")

Questo schema evita un problema comune in cui il file potrebbe sparire tra il controllo e la chiamata a open. Prova direttamente. Se fallisce, intercetta il fallimento.

Evita anche di silenziare gli errori catturando tutto e non facendo nulla. Non fare così:

try:
    something()
except:
    pass

A meno che tu non sappia davvero cosa stai facendo, questo è il posto dove i bug vanno a nascondersi e moltiplicarsi. Se proprio devi silenziare, sii specifico:

try:
    something()
except TimeoutError:
    # okay to ignore in this case
    pass

E registra gli errori da qualche parte. Ingoiarli completamente significa che il te stesso futuro non avrà idea di cosa sia andato storto.

Eccezioni integrate vs personalizzate

Python offre un sacco di eccezioni già pronte, e coprono un numero sorprendente di casi. Probabilmente ti sei già imbattuto in alcune:

  • ValueError: quando qualcosa ha il tipo giusto ma un valore non valido, come int("hello").
  • TypeError: quando provi a usare un'operazione sul tipo sbagliato, come sommare una stringa e un numero.
  • ZeroDivisionError: l'hai indovinato, divisione per zero.
  • FileNotFoundError: quando provi ad aprire un file che non c'è.
  • KeyError: quando manca una chiave in un dizionario.

Queste sono utili e, nella maggior parte degli script o app, più che sufficienti. Ma a volte vorrai sollevare qualcosa di più descrittivo, qualcosa che abbia senso nel mondo del tuo progetto, non solo in quello di Python.

Metti che tu stia scrivendo un'app che elabora ordini online e vuoi sollevare un errore quando un utente prova ad acquistare qualcosa che è esaurito. Potresti usare ValueError, ma è un po' generico. Non dice a chi leggerà il tuo codice in seguito cosa è successo.

Qui brillano le eccezioni personalizzate.

class OutOfStockError(Exception):
    pass

def check_inventory(product_id):
    if not in_stock(product_id):
        raise OutOfStockError(f"Product {product_id} is out of stock.")

Creando l'eccezione personalizzata, aggiungi un livello di significato. E ti dai anche più controllo: puoi intercettare proprio questa situazione specifica:

try:
    check_inventory("shirt-001")
except OutOfStockError:
    print("Sorry, that item is sold out.")

È una piccola cosa, ma rende il codice più facile da capire e mantenere, soprattutto in progetti più grandi. E si integra bene con logging e monitoring: i nomi di eccezioni personalizzate sono molto più facili da cercare di un vago ValueError.

Logging, rilancio e concatenazione delle eccezioni

C'è quel momento che capita durante il debug: vedi un traceback, lo fissi e ti rendi conto che non hai idea del perché qualcosa è fallito. Qui entra in gioco il logging. Non serve solo a registrare gli errori, ma a dare a te in futuro (o al tuo team) gli indizi per capire cosa è andato storto.

Mettiamo che tu stia intercettando un'eccezione e voglia registrarla prima di proseguire:

import logging
logging.basicConfig(level=logging.ERROR)

try:
    do_something()
except ValueError as e:
    logging.error("Failed to do something: %s", e)
    raise

Quel raise finale è importante: rilancia la stessa eccezione dopo averla registrata. Senza di esso, avresti semplicemente ingoiato l'errore. A volte va bene, ma di solito no.

Poi c'è il trucco raise from. Serve quando stai gestendo un errore ma devi sollevarne un altro, e non vuoi perdere quello originale. Python permette di concatenarli:

try:
    connect_to_database()
except TimeoutError as e:
    raise ConnectionError("Database unavailable.") from e

Così il traceback racconta l'intera storia. Ottieni il nuovo ConnectionError, ma vedi anche il TimeoutError che l'ha causato. 

Puoi anche sopprimere l'errore originale (di solito non dovresti) così:

raise ConnectionError("Just this error, nothing else.") from None

Ma a meno che tu non abbia una buona ragione, mantenere l'intera catena aiuta tutti a capire cosa è andato storto e come si è innescato a cascata.

Puoi imparare le basi del logging in Python dal nostro tutorial Logging in Python

Esempi reali e casi d'uso

Parlare di gestione delle eccezioni in astratto è una cosa, ma tutto si chiarisce quando la vedi in codice reale.

Prendi l'input utente, per esempio. Chiedi a chiunque abbia mai costruito uno strumento da riga di comando o un validatore di form: gli utenti inseriranno le cose più strane. Chiedi un numero? Qualcuno digiterà “twelve”. O incollerà un numero di telefono. O premerà semplicemente Invio. Succede.

Invece di scrivere una lunga lista di controlli “e se”, puoi fare così:

while True:
    user_input = input("Enter a number: ")
    try:
        number = int(user_input)
        break
    except ValueError:
        print("Try again with a whole number.")

Questo codice non va in panico quando riceve input spazzatura. Dice all'utente di riprovare e cicla finché non va bene. Molto più pulito che accumulare if per ogni edge case.

Eccone un altro: leggere da un file che potrebbe non esistere.

try:
    with open("config.json") as f:
        settings = f.read()
except FileNotFoundError:
    print("Missing config file. Using defaults.")
    settings = "{}"

Non serve controllare se il file c'è. Prova ad aprirlo e, se fallisce, prosegui. Se avessi provato a controllare prima (os.path.exists()), qualcuno avrebbe potuto eliminare il file tra il controllo e l'apertura. È una race condition, non qualcosa che vuoi debuggare.

Le richieste di rete sono un'altra miniera di eccezioni. Non puoi sempre fidarti che internet si comporti. I server vanno giù. Le connessioni cadono. Il DNS fallisce. Quindi, se fai qualcosa del genere:

import requests

try:
    response = requests.get("https://example.com/data")
    response.raise_for_status()
except requests.exceptions.RequestException as e:
    print("Network problem:", e)

Quella classe base RequestException intercetta comodamente praticamente tutto ciò che requests può sollevare, dai timeout alle risposte errate. Non devi scrivere dieci blocchi except diversi a meno che tu non voglia gestirli in modo diverso.

E se stai scrivendo script di automazione o servizi backend, racchiudere la logica chiave in blocchi try‑except può fare la differenza tra un singolo task che fallisce e l'intero sistema che si spegne. Vuoi errori registrati, task recuperabili ritentati e quelli non recuperabili chiusi in modo pulito, non con stack trace criptici che scorrono all'infinito nei log.

Scopri l'automazione in Python, inclusi concetti fondamentali, librerie chiave, lavoro con i dati, miglioramenti con l'IA e best practice, nel nostro tutorial Python Automation: A Complete Guide

Usi avanzati di try-except in Python

A questo punto, probabilmente hai visto quanto può essere flessibile try‑except. Ma la flessibilità ha due facce. È facile passare dall'utile allo sciatto senza volerlo. Ecco come tenere le cose sotto controllo.

Intercetta eccezioni specifiche. Se sai cosa potrebbe andare storto, nominalo:

try:
    result = int(data)
except ValueError:
    # Only catches invalid numbers, not everything else under the sun

Evita except nudi. Non farlo a meno che tu non stia gestendo qualcosa di molto speciale. Catturerà cose come KeyboardInterrupt, SystemExit e altre che probabilmente non vuoi silenziare.

Usa else e finally quando rendono il codice più chiaro. Non infilarli per forza solo perché esistono. Se il percorso normale del tuo codice finisce sepolto dentro un try, forse spostalo in un else.

Mantieni piccoli i blocchi try. Più includi, più è difficile capire quale riga ha causato l'errore. Racchiudi solo la parte che può fallire. 

Registra gli errori quando serve, soprattutto in produzione. Anche se non stai crashando, sapere cosa è fallito (e quando) rende il debug molto più semplice dopo.

Le eccezioni personalizzate non sono obbligatorie, ma aiutano. Se hai problemi specifici dell'app, definisci i tuoi errori. Possono rendere i log più leggibili e il tuo codice più autoesplicativo.

Un'ultima cosa: non usare le eccezioni per il controllo di flusso a meno che non ci sia un modo migliore. È allettante scrivere logiche tipo “prova questo; se fallisce, fai quello”, ma se è qualcosa che ti aspetti avvenga spesso, probabilmente c'è un modo più pulito.

Conclusione

Come ho spiegato in tutto l'articolo, la gestione delle eccezioni non serve solo a evitare crash. Serve a scrivere codice che si aspetta problemi, li gestisce senza drammi e continua, o si spegne in modo sensato. È la differenza tra un utente che riceve un messaggio utile e uno che viene rispedito al terminale con un lungo traceback illeggibile.

Ti consiglio vivamente di approfondire le eccezioni, con alcuni esercizi pratici, nel capitolo Catching Exceptions in Python del nostro corso OOP in Python.

FAQ su Python try-except

Qual è la differenza tra un errore e un'eccezione in Python?

Un errore di solito si riferisce a un problema che impedisce a Python persino di avviare il tuo codice, come due punti mancanti o un refuso in una parola chiave. Questi sono errori di sintassi. Un'eccezione si verifica mentre il codice è in esecuzione, ad esempio quando provi a dividere per zero o ad aprire un file che non esiste. Le eccezioni possono essere intercettate e gestite in modo che il tuo programma non crashi.

È sbagliato usare un except nudo in Python?

Sì, nella maggior parte dei casi. Un except nudo cattura tutto, comprese cose che non intendevi catturare, come interruzioni da tastiera o segnali di uscita del sistema. Questo rende il debug difficile. È meglio intercettare eccezioni specifiche, come ValueError o FileNotFoundError, così sai esattamente cosa stai gestendo.

Quando dovrei usare else in un blocco try-except?

Usa else quando vuoi eseguire del codice solo se nel blocco try non si è verificata alcuna eccezione. Aiuta a mantenere separata la logica del percorso di successo dalla logica di gestione degli errori, il che può rendere il codice più leggibile e manutenibile.

A cosa serve finally se ho già un blocco except?

finally viene eseguito comunque, che ci sia un errore o meno. È perfetto per la pulizia: chiudere file, rilasciare risorse, eseguire rollback di transazioni e così via. Anche se si verifica un errore o esci in anticipo, finally verrà comunque eseguito.

Dovrei sempre usare `try-except` invece di controllare prima le condizioni?

Non sempre, ma spesso è meglio provare direttamente e catturare l'errore se fallisce. Gli sviluppatori Python chiamano questo EAFP, “Easier to Ask Forgiveness than Permission”. È più veloce ed evita certi bug, soprattutto quando qualcosa può cambiare tra il controllo e l'azione (come un file che viene eliminato).


Derrick Mwiti's photo
Author
Derrick Mwiti
Argomenti

I migliori corsi DataCamp

Corso

Introduzione al Testing in Python

4 h
24.8K
Diventa un esperto dei test Python: Impara i metodi, crea controlli e assicurati che il codice sia privo di errori con pytest e unittest.
Vedi dettagliRight Arrow
Inizia il corso
Mostra altroRight Arrow
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

Mostra altroMostra altro