Menu

Type hint in Python: annotazioni per funzioni, liste, dict e altro

Cosa sono i type hint di Python, quando aiutano e la sintassi per annotare variabili, firme di funzione, contenitori e valori opzionali.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Annotazioni che descrivono, non impongono

Un type hint è una nota che attacchi a un nome, di solito a un parametro di funzione, per dire "questo dovrebbe essere un int", "questa funzione restituisce una lista di stringhe" e così via. Python non li controlla durante l'esecuzione. Passare una stringa dove hai annotato un int non solleva alcun errore. Il tuo editor e gli strumenti esterni (mypy, pyright, Pylance di VS Code basato su Pyright) leggono i type hint e ti avvisano prima che il codice venga eseguito.

Il caso più semplice possibile:

name: str annota il parametro. -> str annota il valore restituito. Entrambe le chiamate vengono eseguite. La seconda è sbagliata (un type checker statico la segnalerebbe), ma Python la elabora senza problemi perché 42 supporta l'interpolazione con f"{...}".

Questo è il modello mentale cruciale: i type hint sono documentazione che una macchina può leggere. Non cambiano il comportamento in esecuzione.

Perché scomodarsi?

Tre vantaggi concreti, in ordine di quanto rapidamente ripagano:

  1. Il tuo editor diventa più intelligente. L'autocompletamento mostra i metodi giusti, le rinomine si propagano correttamente e passando il mouse su una variabile vedi il suo tipo.
  2. Le firme delle funzioni si descrivono da sole. def fetch(url: str, timeout: float = 5.0) -> dict: dice a chi legge esattamente cosa passare e cosa riceverà, senza bisogno di leggere il corpo.
  3. I type checker scovano gli errori prima che tu esegua il codice. Lanciare mypy . su un progetto fa emergere il tipo di bug che spesso sfugge ai test unitari: None restituito dove ti aspettavi un valore, un dict usato dove andava una lista.

Per uno script di un solo file, che usi solo tu e solo oggi, lascia perdere i type hint. Per qualsiasi cosa su cui tornerai o che condividerai, i quindici secondi che servono per scriverli si ripagano entro un'ora.

Tipi integrati di base

Per nessuno di questi serve un import:

Le annotazioni delle variabili (name: str = "Rosa") raramente sono necessarie: Python deduce il tipo dal lato destro. Tienile per parametri, tipi di ritorno e per il caso occasionale in cui il tipo dedotto è ambiguo.

Le funzioni che non restituiscono nulla usano -> None:

Liste, dict, tuple e set

I contenitori hanno bisogno di un'informazione in più: cosa contengono. Il Python moderno ti permette di usare direttamente le parentesi quadre sui tipi integrati:

Leggendoli ad alta voce:

  • list[float]: una lista di float.
  • dict[str, int]: un dict con chiavi stringa e valori int.
  • tuple[float, float]: una tupla di esattamente due float.
  • set[str]: un set di stringhe.

La sintassi list[...], dict[...] funziona da Python 3.9 in poi. Nel codice più vecchio vedrai List, Dict, Tuple importati da typing: stesso significato, grafia più vecchia.

Valori opzionali

"Potrebbe essere None" è un caso comune. Ha due grafie equivalenti: vanno bene entrambe, ma la più recente si legge meglio:

str | None significa "una stringa, oppure None". La sintassi con | funziona da Python 3.10 in poi. Nel codice più vecchio vedrai Optional[str] dal modulo typing, che significa la stessa cosa.

Chi chiama la funzione e vede -> str | None sa che deve controllare se il risultato è None prima di usarlo: è proprio questo lo scopo dell'annotazione.

Tipi unione: questo o quello

Quando un valore può essere di diversi tipi, usa |:

Puoi unire più di due tipi. int | str | float significa "uno qualsiasi di questi tre".

Annotare variabili dentro le funzioni

Il più delle volte Python riesce a capire il tipo di una variabile locale dal suo valore iniziale. Un'annotazione ti serve solo quando:

  • Il contenitore parte vuoto e il type checker non può indovinarne il contenuto.
  • Il valore potrebbe essere di diversi tipi e vuoi impegnarti su uno.
  • Vuoi documentare l'intenzione per chi legge.

typing.Any è la via di fuga: "non voglio annotare questo in modo preciso". Usalo con parsimonia. Abusare di Any rende inutili tutti gli altri type hint.

Annotare le classi

Gli attributi di classe e le firme dei metodi si annotano come qualsiasi altra funzione:

Le dataclass richiedono davvero le annotazioni di tipo: il decoratore @dataclass le legge per generare __init__ e __repr__. È l'unico caso in cui le annotazioni influenzano il comportamento in esecuzione.

Tuple e il caso "lunghezza qualsiasi"

tuple[...] ha due forme che confondono chi inizia:

  • tuple[float, float]: esattamente due float.
  • tuple[int, ...]: un numero qualsiasi di int. I ... (un vero elemento sintattico del sistema di tipi) significano "e così via".

Callable e alias di tipo

Quando una funzione riceve o restituisce un'altra funzione, usa Callable:

Callable[[int], int] significa "una funzione che riceve un int e restituisce un int".

Quando un'annotazione diventa ripetitiva, dalle un nome:

Un alias è solo una normale assegnazione Python. Ovunque useresti la forma lunga, funziona il nome breve.

Eseguire un type checker

L'interprete di Python ignora i type hint. Per verificarli davvero, installa un type checker. mypy è l'originale; pyright (usato da Pylance di VS Code) è più veloce.

pip install mypy
mypy your_project/

La prima esecuzione farà emergere errori in punti che non avevi notato. Risolvili un po' alla volta: # type: ignore silenzia una singola riga quando devi andare avanti.

Gli IDE moderni eseguono il controllo dei tipi di continuo mentre scrivi, quindi la maggior parte dei riscontri arriva prima ancora che tu salvi.

Quando i type hint non sono adatti

  • Script esplorativi veloci. Le annotazioni aggiungono attrito a codice che vive un'ora.
  • Codice molto dinamico. Metaprogrammazione, sistemi di plugin e schemi simili spesso vanno oltre ciò che il sistema di tipi riesce a descrivere. Annota l'API esterna e lascia più liberi gli interni.
  • Librerie di terze parti senza tipi. Se una libreria che importi non ha informazioni sui tipi, Any si infiltra nel tuo codice. Va bene così: non è codice tuo da annotare.

Per tutto ciò che sta nel mezzo, i type hint sono una piccola abitudine con un grande ritorno. Il costo è qualche tasto in più per ogni firma di funzione. Il guadagno sono meno bug, refactoring più facili e codice che si documenta da solo.

Prossimo argomento: moduli e import

Ora hai tutti gli strumenti a livello di funzione: argomenti, decoratori, type hint. Più avanti vedremo come Python organizza il codice su più file: moduli, pacchetti e il sistema di import.

Domande frequenti

Cosa sono i type hint in Python?

I type hint sono annotazioni che descrivono i tipi attesi di variabili, parametri di funzione e valori restituiti. Python stesso non li fa rispettare durante l'esecuzione: servono agli strumenti (IDE, linter, type checker come mypy o pyright) e alle persone che leggono il codice.

I type hint rendono Python più veloce?

No. L'interprete Python ignora i type hint durante l'esecuzione. Il guadagno è nel tuo ciclo di sviluppo: meno errori di battitura grazie all'editor, firme di funzione più chiare, refactoring più sicuri.

Quando dovrei aggiungere i type hint?

Aggiungili alle firme delle funzioni pubbliche: parametri e tipi di ritorno. Usali con parsimonia dentro il corpo delle funzioni, solo dove il tipo di una variabile non è ovvio. Negli script usa e getta sono facoltativi. Nel codice condiviso e nelle librerie si ripagano in fretta.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA