Perché ricevo 'NoneType' object is not subscriptable in Python?

👤 Iniziato da @serapionesantoro
📅 31/12/2025 17:01
📁 Programmazione 🌐 IT
Avatar di serapionesantoro
Ciao a tutti! Stavo lavorando a uno script per gestire dati JSON in un mio progetto personale, quando all'improvviso mi sono imbattuto in questo errore frustrante. Uso Python 3.9 e il problema si presenta quando provo ad accedere a un elemento da quello che pensavo fosse un dizionario. Ecco un frammento di codice che riproduce l'errore:

```python
def get_user_data(user_id):
# Simulo una query che a volte non trova risultati
if user_id > 100:
return None
return {'name': 'Mario', 'age': 30}

data = get_user_data(101)
print(data['name']) # Qui scatta l'errore
```

L'errore esatto è: **TypeError: 'NoneType' object is not subscriptable**. Ho già verificato che la funzione possa effettivamente restituire None, e ho provato a aggiungere un controllo con `if data is not None:` prima dell'accesso, che risolve il caso. Ma mi chiedo: è considerata buona pratica restituire None in questi casi? O sarebbe meglio sollevare un'eccezione personalizzata o usare un dizionario vuoto? Voi come gestite situazioni simili con funzioni che possono ritornare valori 'vuoti'? Grazie mille per i consigli!
Avatar di rosariagalli77
Ah, questo errore "NoneType" è un classico! Ti capisco, quando capita mi fa salire la frustrazione a mille... Nel tuo caso, il problema nasce proprio quando `get_user_data` restituisce None invece di un dizionario. Hai fatto benissimo ad aggiungere il controllo `if data is not None`, ma vediamo le alternative:

Personalmente odio quando una funzione restituisce valori misti (dict o None). Trovo più elegante sollevare un'eccezione personalizzata se si tratta di un caso eccezionale:

```python
class UserNotFoundError(Exception):
pass

def get_user_data(user_id):
if user_id > 100:
raise UserNotFoundError(f"User {user_id} non trovato")
return {'name': 'Mario', 'age': 30}
```

Altrimenti, se "nessun risultato" è un caso frequente e previsto, meglio restituire un dizionario vuoto. Così eviti di dover gestire eccezioni ovunque:

```python
def get_user_data(user_id):
if user_id > 100:
return {}
return {'name': 'Mario', 'age': 30}
```

Nella mia esperienza, sollevare eccezioni è più pulito quando parliamo di errori "gravi", mentre i dizionari vuoti sono ottimi per query dove il risultato nullo è accettabile. Consiglio vivamente di usare type hinting (`-> dict | None` o `-> dict`) per rendere esplicito il comportamento!
Avatar di sageesposito18
Ecco, l'errore "NoneType" è una delle bestemmie in codice che ho maledetto più spesso pure io! Nel tuo caso, la radice è proprio quel ritorno di `None` quando user_id > 100.

Io schifo profondamente i **valori misti** (dict o None) perché diventano trappole per i colleghi - o per te stesso fra 3 mesi. La scelta dipende dalla logica:

1. **Se "user non trovato" è un'eccezione** (es. ID deve esistere): allora **solleva un'eccezione custom** come suggerito da @rosariagalli77. È esplicito e blocca l'esecuzione, costringendo a gestire l'errore.

2. **Se è un caso atteso e frequente** (es. query su dati volatili): **restituisci un dizionario vuoto `{}`**.
Perché? Perché puoi comunque accedere in sicurezza con `data.get('name', 'Valore di default')` senza crash, e mantieni la compatibilità con codice che si aspetta un dict.

Personalmente, **opto per `{}` nel 90% dei casi**: evita try/except ovunque, e gestire valori vuoti con metodi come `.get()` o verifiche su `if data:` è più pulito. L'ho imparato a mie spese dopo aver spaccato tre tastiere per 'NoneType' a mezzanotte!

Se scegli le eccezioni, documenta la funzione con un bel :raises UserNotFoundError: così almeno chi legge è avvisato. 😉
Avatar di albericobernardi
Beh, ragazzi, mi sembra che stiate facendo una diatriba da saggi, ma io aggiungo il mio due soldi. Quell'errore è uno dei più comuni e fastidiosi in Python. Quando scrivo script, mi capita spesso di dover gestire dati che potrebbero o meno essere presenti. Tornando alla domanda, credo che la scelta di come gestire un "valore vuoto" sia più una questione di contesto che di dogma.

Se "utente non trovato" è un evento raro e merita di bloccare l'applicazione per richiamare l'attenzione, allora sollevare un'eccezione personalizzata è la scelta giusta. Ma, come ha detto giustamente @sageesposito18, se "nessun risultato" è frequente e normale, allora restituisci un dizionario vuoto. Questo modo di procedere è più pulito e sicuro, e non devi riempire il codice di controlli ovunque.

Vi parlo dall'esperienza: ho avuto un progetto dove i dati erano molto volatili, e restituire un dizionario vuoto `{}` ha salvato molte ore di debugging su errori simili a quello di @serapionesantoro. Inoltre, con `data.get('name', 'Valore di default')` puoi gestire i casi mancanti senza tanti problemi.

Un altro punto: se preferite lanciare un'eccezione, assicuratevi che sia davvero eccezionale. Troppe eccezioni ovunque possono fare più male che bene. Perciò, ponderate bene le vostre scelte e, soprattutto, documentatele bene nel codice. Niente è peggio che tornare su un progetto vecchio e chiedersi perché si sia optato per quella soluzione.

Insomma, non c'è una regola assoluta, ma conoscendo i propri dati e le proprie esigenze, si può fare la scelta più adatta.
Avatar di aureliomariani10
Beh, che casino con questo errore "NoneType", eh? Mi fa imbestialire ogni volta, come quando provo a montare un mobile IKEA e finisco con le gambe al contrario – ma alla fine, con un po' di testardaggine, si risolve. Ascoltate, @serapionesantoro, hai ragione a chiederti come gestire quel None: io preferisco restituire un dizionario vuoto {} quando "nessun risultato" è un caso normale, come suggerito da @sageesposito18 e @albericobernardi. È più fluido, ti evita di spargere try/except ovunque e puoi usare .get() per difenderti. Però, se è un guaio serio – tipo dati critici che devono esserci – allora un'eccezione personalizzata è da urlo, per non fingere che vada tutto bene. Dalla mia esperienza in un script per dati volatili, questo ha evitato ore di debugging. Forza, non mollare, dai un'occhiata al libro "Clean Code" per pulire il tuo codice! Che ne dite, voi?
Avatar di serapionesantoro
Ciao Aurelio! Ahah, la metafora IKEA mi ha steso - troppo vero! 😂 Grazie mille per i consigli mirati. Effettivamente nel mio caso un dizionario vuoto è la soluzione più pulita visto che "nessun risultato" è un'evenienza normale. Apprezzo tantissimo la distinzione che fai tra casi normali e errori critici: per i dati opzionali userò `{}` e `.get()`, mentre per quelli obbligatori implementerò un'eccezione custom come suggerisci. "Clean Code" è già nel carrello! La discussione è stata illuminante, direi che il mio dubbio è risolto.

La Tua Risposta

💬

Vuoi partecipare alla discussione?

Accedi o registrati per scrivere la tua risposta e unirti alla conversazione!