Debugging di base
Fare debugging
Sezione intitolata “Fare debugging”È normale trovare errori anche dopo aver scritto il codice. Il debugging (o “debug”) consiste nell’individuarli e correggerli.
Quando qualcosa non funziona, raccogli informazioni, formula un’ipotesi e verifica se spiega il comportamento osservato.
I tre tipi di errori
Sezione intitolata “I tre tipi di errori”1. Errori di sintassi
Sezione intitolata “1. Errori di sintassi”Sono errori nel modo in cui hai scritto l’istruzione. Python li segnala prima che il programma parta.
# Manca i due punti alla fine della riga "if"if x > 0 print(x)# SyntaxError: expected ':'Di solito Python indica il punto in cui ha trovato il problema.
2. Errori durante l’esecuzione
Sezione intitolata “2. Errori durante l’esecuzione”Il codice è valido, ma qualcosa va storto durante l’esecuzione.
lista = [1, 2, 3]print(lista[10]) # Stai chiedendo il decimo elemento, ma ne esistono solo 3!# IndexError: list index out of rangeL’indice richiesto non esiste perché la lista contiene solo tre elementi.
3. Errori logici
Sezione intitolata “3. Errori logici”In questo caso il programma gira senza errori, ma produce risultati sbagliati. Devi confrontare il risultato con quello atteso.
def calcola_media(numeri): return sum(numeri) / len(numeri) - 1 # Bug! Il "-1" non dovrebbe esserci
print(calcola_media([8, 7, 9])) # Stampa 7.0 invece di 8.0: sbagliato!Leggere il messaggio di errore (Traceback)
Sezione intitolata “Leggere il messaggio di errore (Traceback)”Quando trova un errore, Python stampa un traceback: mostra le chiamate che hanno portato al punto dell’errore.
Traceback (most recent call last): File "script.py", line 10, in <module> risultato = dividi(10, 0) File "script.py", line 4, in dividi return a / bZeroDivisionError: division by zeroCome leggerlo: parti dall’ultima riga e vai su.
- Ultima riga: il tipo di errore e la descrizione (
ZeroDivisionError: division by zero) - Righe precedenti: la sequenza di passaggi che ha portato all’errore (prima è stato chiamato
dividi, che è a riga 10, e dentrodividil’errore è a riga 4)
Tecnica 1: usare print() come spia
Sezione intitolata “Tecnica 1: usare print() come spia”Per controllare i valori durante l’esecuzione puoi inserire temporaneamente alcune print().
def calcola_media(voti): print(f"DEBUG: voti ricevuti → {voti}") # Spia: cosa arriva alla funzione? totale = sum(voti) print(f"DEBUG: totale calcolato → {totale}") # Spia: il totale è giusto? media = totale / len(voti) print(f"DEBUG: media calcolata → {media}") # Spia: la media è giusta? return media
risultato = calcola_media([8, 7, 9])print(f"Risultato finale: {risultato}")Quando hai trovato il bug e corretto il codice, ricordati di eliminare le righe di debug prima di consegnare o condividere il programma.
Tecnica 2: il modulo logging
Sezione intitolata “Tecnica 2: il modulo logging”Le print() funzionano, ma hanno un problema: devi ricordarti di eliminarle tutte. Il modulo logging è più elegante: puoi accenderlo o spegnerlo con una sola riga.
import logging
# Questa riga "accende" tutti i messaggi di debuglogging.basicConfig(level=logging.DEBUG)
def calcola_media(voti): logging.debug(f"Voti ricevuti: {voti}") totale = sum(voti) logging.debug(f"Totale: {totale}") return totale / len(voti)
calcola_media([8, 7, 9])I livelli di gravità, dal meno al più grave:
| Livello | Quando usarlo |
|---|---|
DEBUG |
Dettagli per il debug |
INFO |
Informazioni generali (“il programma è partito”) |
WARNING |
Qualcosa di strano, ma il programma continua |
ERROR |
Qualcosa è andato storto |
CRITICAL |
Errore gravissimo |
Tecnica 3: il debugger interattivo pdb
Sezione intitolata “Tecnica 3: il debugger interattivo pdb”pdb permette di mettere in pausa il programma durante l’esecuzione e ispezionarne lo stato.
def funzione_problematica(x, y): breakpoint() # Il programma si ferma qui e aspetta i tuoi comandi risultato = x / y return risultato
funzione_problematica(10, 2)Quando il programma si ferma, puoi scrivere comandi:
| Comando | Significato |
|---|---|
n |
Esegui la riga successiva (next) |
s |
Entra dentro una funzione (step) |
p nome_variabile |
Stampa il valore di una variabile |
c |
Continua fino al prossimo punto di pausa (continue) |
q |
Esci dal debugger (quit) |
Tecnica 4: il debugger grafico (VS Code o PyCharm)
Sezione intitolata “Tecnica 4: il debugger grafico (VS Code o PyCharm)”Se usi un editor come VS Code o PyCharm, hai a disposizione un debugger grafico molto più comodo di pdb:
- Clicca sul numero di riga per aggiungere un punto di pausa (breakpoint)
- Avanza riga per riga con i pulsanti
- Guarda tutte le variabili in una finestra apposita, senza dover digitare nulla
Trucchi utili
Sezione intitolata “Trucchi utili”Controlla il tipo di una variabile
Sezione intitolata “Controlla il tipo di una variabile”A volte il bug è che una variabile contiene un tipo di dato inaspettato (ad esempio una stringa invece di un numero).
x = qualche_funzione()print(type(x), x) # Stampa sia il tipo che il valoreUsa assert per aggiungere controlli
Sezione intitolata “Usa assert per aggiungere controlli”assert ti permette di scrivere “mi aspetto che questa condizione sia vera: se non lo è, fermati e dimmi perché”.
def calcola_area(base, altezza): assert base > 0, f"La base deve essere positiva, ma ho ricevuto: {base}" assert altezza > 0, f"L'altezza deve essere positiva, ma ho ricevuto: {altezza}" return base * altezza
calcola_area(5, 3) # Funziona, area = 15calcola_area(-1, 3) # AssertionError: La base deve essere positiva, ma ho ricevuto: -1Isola il problema
Sezione intitolata “Isola il problema”Se il bug è in un programma lungo, crea un piccolo programma separato che riproduce solo il problema. Questo ti aiuta a:
- Eliminare tutto il codice non rilevante
- Concentrarti solo sul pezzo problematico
- Testare soluzioni più rapidamente