f in x
Gestione Errori in Python — try except finally e logging per codice robusto
> cd .. / HUB_EDITORIALE > Visualizza in Inglese
Sviluppo di siti web

Gestione Errori in Python — try except finally e logging per codice robusto

[2026-06-21] Author: Ing. Calogero Bono

Hai mai visto un'applicazione Python bloccarsi perché un file non esisteva o un'API ha risposto con un errore 500? Succede a tutti. E quando succede in produzione, il cliente vede una schermata bianca o un errore criptico. Noi, di Meteora Web, lo abbiamo visto decine di volte nei progetti che ci arrivano: codice che funziona in locale ma esplode in produzione. La differenza? Una gestione degli errori solida: try, except, finally e logging. Non è noiosa teoria: è la differenza tra un'applicazione che si riprende e una che si spegne. In questa guida ti mostriamo come implementarla.

Perché la gestione degli errori è cruciale per un codice Python robusto?

Quando un'eccezione non viene catturata, Python interrompe l'esecuzione del programma. In un'applicazione web significa 500 Internal Server Error; in uno script batch significa processo fallito senza preavviso. Un cliente che abbiamo seguito (un e-commerce di abbigliamento, di cui abbiamo gestito il sistema ERP) aveva un modulo di import ordini che si bloccava su un singolo prodotto malformato. Risultato: centinaia di ordini non elaborati. Abbiamo aggiunto try/except con logging per saltare il record problematico e continuare l'import, registrando l'errore per il controllo manuale. Il processo non si è più fermato.

Sponsored Protocol

La gestione degli errori non serve solo a evitare crash: serve a rendere il programma prevedibile. L'utente deve sapere che qualcosa è andato storto, ma il sistema non deve andare giù. E tu, sviluppatore, devi poter capire cosa è successo. Ecco perché il logging non è opzionale.

Come funzionano try, except e finally in Python?

Il blocco try contiene il codice che potrebbe fallire. Subito dopo si mettono uno o più blocchi except per catturare eccezioni specifiche. Il blocco finally viene eseguito sempre, sia in caso di eccezione che di successo, ed è ideale per rilasciare risorse (chiudere file, connessioni).

try:
    file = open('dati.txt', 'r')
    contenuto = file.read()
    numero = int(contenuto.strip())
except FileNotFoundError:
    print('File non trovato. Uso valore predefinito.')
    numero = 0
except ValueError:
    print('Contenuto del file non è un intero valido.')
    numero = 0
finally:
    # Chiude il file anche se c'è stata un'eccezione
    try:
        file.close()
    except NameError:
        pass  # file non è mai stato aperto

Nota l'except FileNotFoundError specifico: non un generico except:. Catturare tutto nasconde bug. Nel caso in cui il file non esista, il finally tenta di chiudere, ma se l'apertura è fallita la variabile file non esiste: ecco il NameError gestito con un secondo try/except. Situazione reale.

Sponsored Protocol

Il blocco else è opzionale e si esegue solo se nessuna eccezione è stata sollevata. Utile per codice che deve essere eseguito solo in caso di successo:

try:
    result = rischiosa_operazione()
except ValueError:
    print('Operazione fallita')
else:
    print('Operazione riuscita, valore:', result)

Quali eccezioni catturare e come organizzarle per non nascondere bug?

La regola d'oro: cattura eccezioni specifiche, non generiche. Un except Exception cattura tutto, compreso KeyboardInterrupt e SystemExit (in realtà non derivano da Exception, ma molti commettono l'errore di usare except: senza specificare). Usa invece i tipi documentati: ValueError per input non validi, TypeError per operazioni tra tipi incompatibili, FileNotFoundError, ConnectionError ecc.

Se hai più eccezioni da gestire allo stesso modo, puoi raggrupparle in una tupla:

try:
    valore = int(input('Inserisci un numero: '))
    risultato = 10 / valore
except (ValueError, ZeroDivisionError) as e:
    print(f'Errore di input o divisione: {e}')

Un errore comune è catturare e passare oltre senza traccia. Noi vediamo spesso codice come:

Sponsored Protocol

try:
    fai_qualcosa()
except:
    pass  # non fare nulla

Questo è pericolosissimo: l'errore viene ingoiato, e nessuno saprà mai che c'è stato un problema. Il sistema potrebbe funzionare apparentemente, ma con dati corrotti o incomplete. Sempre loggare, almeno a livello WARNING o ERROR.

Come integrare il logging per tenere traccia degli errori?

Il modulo logging di Python è lo strumento standard per tracciare eventi. È più potente di print perché permette di configurare formati, livelli (DEBUG, INFO, WARNING, ERROR, CRITICAL), e destinazioni (file, console, email).

Configurazione base all'avvio del programma:

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('app.log', encoding='utf-8'),
        logging.StreamHandler()   # anche su console
    ]
)

Dopodiché, nei blocchi except usa logging.error() o logging.exception() per includere automaticamente il traceback:

try:
    with open('configurazione.json') as f:
        config = json.load(f)
except FileNotFoundError:
    logging.warning('File di configurazione non trovato, uso default')
    config = {}
except json.JSONDecodeError as e:
    logging.error('Errore nel parsing JSON: %s', e)
    raise  # rilancia se non puoi recuperare

La funzione logging.exception() logga il messaggio e il traceback, ma va chiamata solo all'interno di un except. Ottimo per debug.

Sponsored Protocol

Noi, di Meteora Web, abbiamo strutturato il logging in tutte le nostre applicazioni Laravel e Python per avere una cronologia degli errori su file. Quando su un server si è rotto il rinnovo automatico dei certificati SSL, i log ci hanno permesso di identificare il problema in pochi minuti, senza far andare offline il cliente.

Quali errori comuni evitare nella gestione delle eccezioni?

Ecco alcuni anti-pattern che vediamo spesso:

  • Troppo poco specifico: except: o except Exception: senza motivo.
  • Bloccare eccezioni che dovrebbero propagarsi: a meno che tu non possa recuperare realmente, rilancia con raise.
  • Non usare finally: se apri un file o una connessione, assicurati di chiuderla sempre, anche in caso di errore. with statement aiuta, ma per risorse custom usa finally.
  • Mischiare logging e print: scegli il logging, configurato per produzione (es. solo ERROR su file).
  • Ignorare le eccezioni built-in: StopIteration, KeyboardInterrupt non vanno catturati a meno di esigenze specifiche.

Cosa fare adesso

Non aspettare che un errore in produzione ti svegli la notte. Ecco tre azioni concrete da fare oggi:

Sponsored Protocol

  1. Analizza il tuo codice attuale: cerca blocchi di codice che possono sollevare eccezioni (divisioni, accesso a file, chiamate API, parsing) e verifica che abbiano try/except con eccezione specifica.
  2. Sostituisci print con logging: configura un logger con un file e livelli adeguati. Per esempio, durante lo sviluppo usa DEBUG, in produzione ERROR.
  3. Aggiungi un handler per le eccezioni non catturate: usa sys.excepthook per loggarle:
import sys
import logging

def handle_uncaught_exception(exc_type, exc_value, exc_traceback):
    logging.critical("Eccezione non gestita", exc_info=(exc_type, exc_value, exc_traceback))

sys.excepthook = handle_uncaught_exception

Questa è la tua rete di sicurezza. Se qualcosa sfugge, almeno lo registri.

Questa guida è un approfondimento del nostro Pillar su Python per Sviluppatori, dove trovi tutto il percorso completo. Per documentazione ufficiale: Errori ed eccezioni e Logging.

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Ingegnere Informatico, co-fondatore di Meteora Web. Esperto in architetture software, sicurezza informatica e sviluppo sistemi scalabili.
[ Read Full Dossier ]

> METEORA_WEB // WEB AGENCY

Costruiamo la presenza digitale che la tua azienda merita.

Siti web, social, pubblicità online, e-commerce e hosting performante: ingegnerizzati con metodo da ingegneri informatici a Sciacca, per tutta Italia.

> MW_JOURNAL

> READ_ALL()