ProgrammazioneSviluppatore Backend

Descrivi i meccanismi di gestione delle eccezioni in Python. Come funziona il blocco try/except/finally, a cosa serve raise e quali sono le insidie più comuni?

Supera i colloqui con l'assistente IA Hintsage

Risposta

In Python, la gestione delle eccezioni è implementata attraverso le strutture try/except/else/finally e l'operatore raise.

try definisce un blocco di codice protetto. Se all'interno si verifica un'eccezione, il controllo passa al blocco except più vicino. Se non ci sono eccezioni, viene eseguito il blocco else, se presente. Il blocco finally viene sempre eseguito, indipendentemente dal fatto che ci sia stata o meno un'eccezione (ad esempio, per liberare risorse).

L'operatore raise genera esplicitamente un'eccezione o ripete quella corrente (nel blocco except senza specificare il tipo).

Esempio:

try: x = 1 / 0 except ZeroDivisionError as e: print(f"Errore: {e}") else: print("Non ci sono errori") finally: print("Sempre eseguito")

Risultato:

Errore: division by zero
Sempre eseguito

Finezze:

  • Con i gestori annidati, è importante l'ordine degli except: dai tipi specifici ai più generali (altrimenti i tipi specifici non verranno gestiti).
  • Il blocco finally non può prevenire il rilancio di un'eccezione (se dentro finally si inserisce raise — è valida l'ultima "errore" corrente).

Domanda trabocchetto

Domanda: «Cosa succede se in entrambi i blocchi try e finally si lancia raise con eccezioni diverse?»

Risposta: L'eccezione da finally "sovrascrive" l'eccezione da try: all'esterno uscirà quella generata da finally.

def foo(): try: raise ValueError("in try") finally: raise IndexError("in finally") try: foo() except Exception as e: print(repr(e)) # Stampa: IndexError('in finally')

Esempi di errori reali a causa della mancanza di conoscenza delle finezze dell'argomento


Storia

Nel processo ETL, la connessione al database veniva sempre chiusa nel blocco finally, ma si dimenticava che all'interno di finally potrebbe verificarsi un'eccezione (ad esempio, se la connessione era già chiusa). Risultato — un'eccezione "nascosta" da finally assorbiva completamente l'eccezione dal codice principale, complicando drasticamente il debugging.


Storia

Utilizzavano catene di più except: da un generico except Exception sopra i particolari. Di conseguenza, tutti i specifici except rimanevano "morti" — le eccezioni a livello inferiore non venivano catturate separatamente, rendendo difficile la gestione degli errori specifici.


Storia

In un servizio web, nel blocco except si dimenticava di propagare l'eccezione ulteriormente attraverso "raise", registrando l'errore, ma permettendo al flusso di continuare. Di conseguenza, gli errori reali venivano "persi" e il programma continuava a funzionare in uno stato non corretto.