Corso Python / Leggere traceback e usare debugger e logging
Per individuare un errore, leggi prima il tipo di eccezione e il messaggio finale del traceback, poi riproduci l’ingresso che l’ha causato. Il debugger permette di osservare lo stato durante l’esecuzione; logging registra gli eventi scelti dal programma con un livello di gravità.
Ridurre il problema a un caso riproducibile
Parti dall’ultima riga del traceback e risali ai file e alle righe del tuo codice nella catena di chiamate. La riga segnalata mostra dove il guasto è emerso, non sempre dove è stato introdotto: un valore errato può essere stato preparato prima e passato a una libreria perfettamente funzionante.
Annota il comando, l’interprete del progetto, i dati di prova e il risultato atteso. Riduci il caso rimuovendo le parti non necessarie, senza eliminare proprio le condizioni che lo producono. Correggere il primo errore reale è più utile che modificare indiscriminatamente il codice delle dipendenze.
In VS Code, con il progetto e l’interprete corretti selezionati e il supporto Python Debugger disponibile, apri il file e imposta un breakpoint nel margine accanto alla riga da osservare. Avvia Run and Debug, scegli l’esecuzione del file Python corrente quando richiesto e controlla Variables e Call Stack mentre l’esecuzione è sospesa. Usa Step Over per seguire le istruzioni e osserva i dati prima del punto di errore. La guida ufficiale al debugger Python in VS Code descrive configurazioni e controlli.
Nell’esempio seguente puoi fermarti sulla condizione che controlla i valori negativi e ispezionare amounts. La distinzione tra intercettare e propagare un errore è approfondita nella guida alle eccezioni.
Eseguire un calcolo con logging
Salva il codice completo come logging_demo.py, in UTF-8, in una cartella di esercizio. Avvialo dal terminale con python logging_demo.py, usando l’interprete del progetto. Fuori dall’ambiente virtuale su macOS o Ubuntu usa python3 se è il nome dell’interprete scelto. Non occorrono pacchetti esterni.
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(message)s")
logger = logging.getLogger(__name__)
def calculate(amounts):
logger.debug("count=%s", len(amounts))
if any(x < 0 for x in amounts):
raise ValueError("negative amount")
return sum(amounts)
try:
total = calculate([3500, 8000, 2500])
except ValueError:
logger.exception("calculation failed")
raise SystemExit(1)
else:
logger.info("total=%s", total)
print("finished")
Sul canale di uscita standard, stdout, il risultato previsto è soltanto:
finished
Sul canale di errore standard, stderr, viene inoltre emesso INFO:total=14000. Un terminale può visualizzarli insieme, ma restano due flussi differenti. Il messaggio DEBUG sul numero di elementi non compare con la configurazione INFO.
BasicConfig imposta la configurazione di base del logging; qui il programma viene avviato come nuovo processo. In ambienti interattivi già configurati, basicConfig può non modificare i gestori esistenti, quindi non usare l’assenza di un cambiamento come prova che il codice del livello non funzioni. Il logger prende il nome del modulo mediante __name__.
Distinguere livello, canale e stato di uscita
| Livello | Uso tipico |
|---|---|
| DEBUG | Dettagli per la diagnosi |
| INFO | Avanzamento o risultati normali |
| WARNING | Condizione che richiede attenzione |
| ERROR | Operazione fallita |
| CRITICAL | Problema grave per la continuità del programma |
La scelta del livello segue una politica coerente nell’applicazione. Nel nostro caso INFO rende visibile il totale e nasconde count=3. La guida ufficiale a logging spiega livelli e configurazione.
logger.exception, usato nel gestore di un’eccezione, aggiunge al messaggio ERROR anche il traceback. Non provoca da solo un’uscita fallita: il codice deve decidere se recuperare o interrompere. Qui raise SystemExit(1) termina il processo con stato 1 dopo il log di un ValueError non recuperabile; il successivo print non viene eseguito.
Con i dati originali il processo termina con stato 0; con un importo negativo termina con stato 1 e non stampa finished. Subito dopo il comando controlla $LASTEXITCODE in PowerShell oppure echo $? nella shell di macOS o Ubuntu. La documentazione di sys.exit e SystemExit chiarisce il significato dei valori di uscita.
Non dedurre l’ordine temporale completo dall’ordine con cui un sistema riunisce stdout e stderr: acquisizione e buffering possono influire sulla visualizzazione. Se scegli di registrare su file, definisci anche destinazione, rotazione, conservazione e permessi; una chiamata di log non stabilisce da sola queste regole operative.
Provare un errore e ripristinare il comportamento
- Esegui l’originale in un nuovo processo: verifica finished su stdout, INFO:total=14000 su stderr e stato 0.
- In una copia cambia soltanto 8000 in -1 nell’elenco passato a calculate. Verifica ERROR:calculation failed, il traceback con ValueError: negative amount e stato 1. Finished non deve comparire.
- Conservando i dati negativi, cambia il livello iniziale da logging.INFO a logging.DEBUG. Deve comparire anche DEBUG:count=3 prima della segnalazione dell’errore.
- Ripristina dati e livello originali, poi verifica di nuovo il risultato normale.
L’esempio con una lista vuota restituisce un totale zero e non rappresenta una validazione completa dei dati di dominio. Se servono regole ulteriori, rendile esplicite. Evita di sostituire il gestore con un except generico vuoto: rischieresti di stampare finished anche dopo un calcolo fallito.
Registra il contesto utile, senza password, token, intestazioni di autenticazione o interi record personali. Limitare dati e frequenza dei messaggi riduce sia l’esposizione di informazioni sia il consumo di tempo e spazio. L’utente deve ricevere un’indicazione per agire; chi diagnostica il problema ha bisogno del contesto selezionato per ricostruirlo.




