<aside> <img src="notion://custom_emoji/899aa73c-260f-813c-baa9-0003a270e9e6/29eaa73c-260f-8057-931f-007a0ac7402b" alt="notion://custom_emoji/899aa73c-260f-813c-baa9-0003a270e9e6/29eaa73c-260f-8057-931f-007a0ac7402b" width="40px" />

Indice

</aside>

La gestione delle eccezioni

Nella programmazione, non tutto va sempre come previsto. Una 'eccezione' è un evento anomalo, un errore, che si verifica durante l'esecuzione (cioè a run-time) di un programma e che ne interrompe il normale flusso.

In Python, quando si verifica un errore, il programma “solleva” (in inglese raises) un'eccezione. Se questa eccezione non viene “catturata” (ovvero gestita), il programma si arresta bruscamente (va in crash) mostrando un messaggio di errore (il traceback).

flowchart LR
    A([Errore si verifica]) --> B([raise Eccezione])
    B --> C{{Eccezione gestita?}}
    C -->|Sì| D([Codice di gestione<br> dell'errore])
    C -->|No| E[[Crash del programma]]
    E --> F[/Stampa del traceback/]

    %% Definizione degli stili
    classDef error fill:#ffcccc,stroke:#cc0000,stroke-width:2px;
    classDef raise fill:#ffe6cc,stroke:#ff6600,stroke-width:2px;
    classDef decision fill:#fff2b3,stroke:#aa8800,stroke-width:2px;
    classDef handler fill:#ccffcc,stroke:#009900,stroke-width:2px;
    classDef crash fill:#ffd6d6,stroke:#ff0000,stroke-width:2px;
    classDef trace fill:#f2f2f2,stroke:#666666,stroke-width:1px;

    %% Assegnazione degli stili
    class A error;
    class B raise;
    class C decision;
    class D handler;
    class E crash;
    class F trace;

<aside> ✨

I “codici di errore” nei vecchi linguaggi di programmazione

Nei linguaggi più vecchi si usavano codici fittizi come -1 o False per indicare una condizione errore, ad esempio come valori restituiti da una funzione.

Questo modo di programmare mescola il “risultato” della funzione e lo “stato d’errore”, rendendo difficile capire dove sia avvenuto il problema.

Con le eccezioni, il flusso logico e quello d’errore sono separati e più leggibili.

</aside>


Perché gestire le eccezioni?

Immaginiamo, nel nostro progetto “Code Combat”, di aver aggiunto alla classe Player un metodo per calcolare il danno medio inflitto durante il combattimento.

Per farlo, la classe tiene traccia di self.__total_damage_dealt (danno totale inflitto) e self.__total_hits (numero di colpi andati a segno).

Il metodo potrebbe essere scritto così:

# Dentro la classe Player
def get_average_damage(self):
    # Calcola la media: danno totale / numero di colpi
    return self.__total_damage_dealt / self.__total_hits

Cosa succede se chiamiamo questo metodo su un giocatore che è appena entrato nell’arena e non ha ancora sferrato nessun colpo?

gimli = Player("Gimli", 50, 18, 7)
# gimli non ha ancora combattuto, quindi self.__total_hits è 0

print("Calcolo del danno medio di Gimli...")
media = gimli.get_average_damage() # CRASH!
print(f"Danno medio: {media}")

Nel momento in cui il metodo esegue la divisione, self.__total_hits è 0. Python non può dividere un numero per zero e solleva un’eccezione ZeroDivisionError, arrestando l’intero programma.

Dato che non abbiamo fornito nessun gestore di eccezioni, l’eccezione viene catturata dal gestore di default di Python, che visualizza un “traceback” e termina il programma.

Questo è l'output dell'eccezione:

Traceback (most recent call last):
  File "main.py", line 16, in <module>
    media = gimli.get_average_damage() # CRASH!
  File "main.py", line 10, in get_average_damage
    return self.__total_damage_dealt / self.__total_hits
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
ZeroDivisionError: division by zero

Notate come il traceback mostri l'intera catena di chiamate (lo stack):

  1. L'errore avviene nel file Divisione.py, riga 4, dentro la funzione dividi.