Gli errori sono il modo in cui Python ti dice cosa è successo
Ogni errore Python è un oggetto con un tipo, un messaggio e un traceback, cioè la catena di chiamate che ci ha portato. Saperlo leggere bene è in assoluto l'abilità di debug più importante che puoi imparare. Questa pagina è un giro tra gli errori che incontrerai davvero e le abitudini che rendono veloce correggerli.
Per approfondire il funzionamento di try/except e di come sollevare eccezioni tue, la pagina sulle eccezioni spiega la sintassi. Questa pagina parla degli errori specifici e di come leggerli.
Leggere un traceback
Esegui qualcosa che si rompe:
def divide(a, b):
return a / b
def report(values):
for v in values:
print(divide(10, v))
report([5, 2, 0])
Python stampa qualcosa del genere:
Traceback (most recent call last):
File "script.py", line 8, in <module>
report([5, 2, 0])
File "script.py", line 6, in report
print(divide(10, v))
File "script.py", line 2, in divide
return a / b
ZeroDivisionError: division by zero
Leggilo dal basso verso l'alto:
ZeroDivisionError: division by zero: il tipo di eccezione e il messaggio. Questo è cosa è andato storto.return a / bindivide, riga 2: la riga che ha effettivamente sollevato l'errore.print(divide(10, v))inreport, riga 6: la chiamata che l'ha scatenato.report([5, 2, 0])a livello di modulo, riga 8: dove tutto è cominciato.
Il frame in fondo è quasi sempre dove va la correzione. Quando una libreria lancia un errore in profondità nel suo codice interno, risali il traceback fino al primo frame del tuo codice: è la chiamata a cui hai passato un input sbagliato.
Gli errori che incontrerai più spesso
NameError
"Name 'mesage' is not defined." Causato da errori di battitura o dall'uso di una variabile prima di averle assegnato un valore. Nelle versioni recenti, il messaggio di Python di solito suggerisce un probabile nome corretto ("Did you mean 'message'?").
Correzione: controlla l'ortografia e l'ambito. Se il nome esiste solo dentro una funzione, non puoi leggerlo da fuori.
TypeError
"Can only concatenate str (not 'int') to str." Tipo sbagliato per l'operazione. I classici: sommare una stringa a un numero, chiamare qualcosa che non è chiamabile, passare a una funzione il numero sbagliato di argomenti.
Correzione: converti i tipi esplicitamente (str(30), int("30")) o controlla cosa stai passando davvero. Una f-string di solito si legge meglio della concatenazione con + tra tipi diversi: f"age: {30}".
ValueError
"Invalid literal for int() with base 10: 'hello'." Il tipo è giusto (int() accetta una stringa), ma il valore non va bene. Comune con int(), float(), l'interpretazione di date e le funzioni che accettano un argomento con limiti precisi.
Correzione: valida prima di convertire, oppure cattura l'errore e gestiscilo:
KeyError
"KeyError: 'charlie'." La chiave non è nel dict. Tre correzioni idiomatiche, da scegliere in base all'intenzione:
Per un dict in cui le chiavi mancanti devono inizializzarsi da sole, vale la pena dare un'occhiata a collections.defaultdict.
IndexError
"List index out of range." Hai chiesto una posizione che la sequenza non ha.
Correzione: proteggiti con un controllo sulla lunghezza, usa -1 per l'ultimo elemento o usa lo slicing (numbers[5:6] restituisce [] invece di sollevare un errore).
AttributeError
"'NoneType' object has no attribute 'upper'." Hai chiamato un metodo su qualcosa che non ce l'ha. Quasi sempre significa che una variabile è di un tipo inatteso, spesso None quando ti aspettavi un valore vero.
Correzione: scopri da dove arriva quel None. print(type(var)) o un breakpoint subito prima dell'errore sono il modo più veloce. Le funzioni che "a volte falliscono" di solito restituiscono None; controlla il valore restituito prima di chiamarci sopra dei metodi.
ModuleNotFoundError (e ImportError)
import fastapi
"No module named 'fastapi'." Il pacchetto non è installato nell'interprete Python che il tuo script sta usando. Due cause comuni:
- Non l'hai proprio installato. Esegui
python -m pip install fastapinell'ambiente giusto. - L'hai installato, ma in un altro Python. Succede di continuo su macOS quando
pipepythonpuntano a installazioni diverse.
La correzione affidabile è installare con lo stesso interprete con cui esegui:
python -m pip install fastapi
Se usi un ambiente virtuale (e dovresti), assicurati che sia attivo sia prima di pip install sia prima di python script.py.
FileNotFoundError
with open("settings.yaml") as f:
config = f.read()
"[Errno 2] No such file or directory: 'settings.yaml'." Il percorso non esiste rispetto alla cartella da cui sta girando lo script.
Correzione: stampa os.getcwd() all'inizio dello script per verificare dove sta cercando Python. Usa percorsi assoluti o pathlib.Path(__file__).parent / "settings.yaml" per ancorare i percorsi alla posizione dello script stesso.
EOFError
name = input("Name: ")
"EOF when reading a line." input() ha provato a leggere da stdin e non ha ricevuto niente: o l'input arrivava tramite pipe da una sorgente vuota, o hai premuto Ctrl-D al prompt.
Correzione: se l'uso della pipe è legittimo, avvolgi la chiamata:
try:
name = input("Name: ")
except EOFError:
name = "anonymous"
Nell'editor nel browser di queste pagine, l'ambiente simula l'input, quindi lì non incontrerai questo errore.
IndentationError e SyntaxError
IndentationError: expected an indented block after function definition on line 2
Questi sono speciali: scattano prima che il programma parta. Python si è rifiutato di interpretare il file.
IndentationError: il corpo di undef,if,fore simili manca o non è allineato. La maggior parte degli editor mostra l'indentazione; attiva "mostra spazi bianchi" per scovare tab e spazi mescolati.SyntaxError: hai dimenticato i due punti, sbagliato una parentesi o scritto male una parola chiave. Le versioni recenti di Python puntano una freccia (^) sul carattere colpevole.
Correzione: il messaggio di errore indica la riga. Vai a guardare. Se su quella riga non c'è niente di evidentemente sbagliato, controlla la riga sopra: una parentesi non chiusa qualche riga prima si manifesta spesso come errore di sintassi molto più avanti.
RuntimeError
Un contenitore generico per "qualcosa è andato storto durante l'esecuzione e non rientra negli errori più specifici". RecursionError (superata la profondità massima di ricorsione) è una sua variante comune. Il codice delle librerie solleva spesso RuntimeError quando si trova in uno stato non valido.
Correzione: leggi il messaggio; di solito è descrittivo. Se la causa è la ricorsione, trasformala in un ciclo iterativo oppure, in rari casi, alza il limite con sys.setrecursionlimit.
Debug con print
Prima di passare a un vero debugger, print() (o meglio la forma f"{var=}") scova la maggior parte dei bug:
f"{var=}" stampa sia l'espressione sia il suo valore, così non devi riscrivere il nome nella stringa di formato. Esegui lo script, scorri l'output, trova la riga in cui un valore è diventato sbagliato. La maggior parte dei bug "misteriosi" diventa evidente con tre o quattro print ben piazzati.
Togli i print prima di fare commit. Per il codice che rilascerai, logging.debug(...) è più comodo di print: puoi attivare e disattivare i log di debug senza modificare righe.
breakpoint() e pdb
Quando print non basta, breakpoint() ti porta nel debugger interattivo di Python in quel punto:
def discount(price, percent):
breakpoint()
return price * (1 - percent / 100)
discount(100, 20)
Esegui lo script in un vero terminale. Ti ritroverai a un prompt (Pdb). Qualche comando da conoscere:
p variable: stampa una variabile.n: passa alla riga successiva.s: entra dentro una chiamata di funzione.c: continua fino al prossimo breakpoint o alla fine.q: esci.l: mostra il codice attorno alla riga corrente.
I debugger degli IDE (VS Code, PyCharm) offrono lo stesso protocollo con un'interfaccia grafica: breakpoint impostati a margine, un pannello laterale con le variabili. Scegli quello che ti sembra più comodo.
Abitudini che riducono gli errori
- Usa nomi di variabile descrittivi. Metà del rumore da
TypeErroreAttributeErrorsparisce quando non puoi dimenticare cosa c'è in una variabile. - Valida gli input al confine. Interpreta e controlla l'input dell'utente o il contenuto dei file una volta sola, all'inizio della funzione. Il resto del codice può poi fidarsi dei valori.
- Fallisci in modo evidente, non in silenzio. Un
except Exception: passgenerico nasconde proprio gli errori che hai bisogno di vedere. Cattura eccezioni specifiche, gestiscile di proposito e lascia propagare il resto. - Leggi prima il fondo del traceback. Ogni minuto speso a imparare a leggere i traceback ti ripaga cento volte tanto.
La maggior parte degli errori non è un mistero: sono errori di battitura di una riga o tipi sbagliati, con un messaggio chiaro. Fidati del messaggio di errore; di solito ha ragione.
Ce l'hai fatta
Questa è la fine della sezione di riferimento. Sei passato da "cos'è Python?" a variabili, controllo del flusso, collezioni, funzioni, classi, iterazione, dati del mondo reale ed errori. Da qui i prossimi passi hanno la forma di un progetto: scegli qualcosa che vuoi costruire e risali ai pezzi che devi approfondire. Queste pagine saranno ancora qui quando tornerai con una domanda precisa.
Domande frequenti
Cos'è un KeyError in Python?
KeyError viene sollevato quando cerchi in un dict una chiave che non esiste. users["missing"] solleva KeyError: 'missing'. Le alternative sicure sono users.get("missing", default), users.get("missing") (restituisce None) o un controllo esplicito if key in users:.
Cos'è un EOFError in Python?
EOFError (end-of-file, fine del file) viene sollevato quando input() non riesce a leggere niente perché il flusso di input si è chiuso. Lo vedrai più spesso quando a uno script che usa input() arriva una pipe senza dati, o quando premi Ctrl-D nel prompt interattivo. Proteggiti con try/except EOFError se il tuo script deve gestire input da pipe.
Cos'è un ModuleNotFoundError?
ModuleNotFoundError significa che import X non ha trovato un modulo chiamato X. O il pacchetto non è installato (pip install X), oppure è installato in un Python diverso da quello che esegue il tuo codice (molto comune quando hai più versioni di Python). python -m pip install X risolve il secondo caso perché usa lo stesso interprete.
Come si legge un traceback in Python?
Leggilo dal basso verso l'alto. L'ultima riga è il tipo di eccezione e il messaggio: la cosa precisa che è andata storta. Le righe sopra mostrano la catena di chiamate che ci ha portato lì, e di solito il tuo codice è più vicino al fondo. Vai al file e alla riga del frame più in basso che appartiene al tuo codice: è lì che va la correzione.