Aller au contenu
Développement medium

Type hints en Python : annoter et vérifier son code (typing)

10 min de lecture

logo python

Un type hint est une annotation qui indique le type attendu d'une variable, d'un paramètre ou d'une valeur de retour. Python reste un langage à typage dynamique : ces annotations ne sont pas vérifiées à l'exécution, mais elles documentent le code, alimentent l'autocomplétion de l'éditeur et permettent à un outil comme mypy d'attraper des bugs avant de lancer le programme. Ce guide couvre l'annotation des fonctions et variables, le typage des collections (list, dict), les unions (X | None), les alias, et la vérification avec mypy.

Il s'adresse aux développeurs qui veulent un code plus sûr et plus lisible, et à celles et ceux qui utilisent des outils modernes comme Pydantic, FastAPI, les dataclasses ou SQLAlchemy 2.0, tous bâtis sur les annotations de type. Les exemples ont été exécutés avec Python 3.12 et vérifiés avec mypy.

  • Annoter paramètres, valeurs de retour et variables.
  • Typer les collections avec list[int], dict[str, float].
  • Exprimer une valeur optionnelle ou une union avec X | None.
  • Créer des alias de type pour clarifier les signatures.
  • Vérifier votre code avec mypy et comprendre ses limites.

Un type hint (indice de type) est une annotation ajoutée au code pour préciser le type attendu. La syntaxe repose sur deux-points pour les variables et paramètres, et sur -> pour la valeur de retour d'une fonction.

def saluer(nom: str) -> str:
return f"Bonjour {nom}"
age: int = 30

Point essentiel : Python ignore ces annotations à l'exécution. Elles ne convertissent ni ne valident les valeurs. Un appel avec un mauvais type s'exécute quand même.

def double(x: int) -> int:
return x * 2
double("oups") # aucune erreur : renvoie 'oupsoups'

Les annotations sont donc un contrat, pas une contrainte : ce sont des outils externes (mypy, l'éditeur) qui les font respecter. C'est ce qui distingue le type hinting d'un vrai typage statique comme en Java.

L'usage le plus courant est d'annoter les paramètres et la valeur de retour d'une fonction. C'est là que les annotations rendent le plus service : elles décrivent le contrat de la fonction d'un coup d'œil.

def moyenne(notes: list[float]) -> float:
return sum(notes) / len(notes)
def est_majeur(age: int) -> bool:
return age >= 18

Une fonction qui ne renvoie rien s'annote avec None :

def afficher(message: str) -> None:
print(message)

Depuis Python 3.9 (PEP 585), on annote les collections avec les types natifs directement suivis de crochets, sans rien importer :

notes: list[float] = [12.0, 15.5]
ages: dict[str, int] = {"Alice": 30, "Bob": 25}
coord: tuple[int, int] = (10, 20)
tags: set[str] = {"prod", "web"}

Les crochets précisent le type des éléments : list[float] est une liste de flottants, dict[str, int] associe des clés str à des valeurs int.

Une valeur qui peut être absente (None) est très fréquente. Depuis Python 3.10 (PEP 604), on l'exprime avec l'opérateur | :

def chercher_utilisateur(nom: str) -> str | None:
# renvoie l'email, ou None si l'utilisateur n'existe pas
...

Le | sert plus largement à décrire une union de plusieurs types :

def normaliser(valeur: int | str) -> str:
return str(valeur)

Quand un type devient long ou revient souvent, un alias clarifie les signatures. Depuis Python 3.12 (PEP 695), on le déclare avec le mot-clé type :

type Vecteur = list[float]
type Coordonnees = dict[str, tuple[float, float]]
def norme(v: Vecteur) -> float:
return sum(x * x for x in v) ** 0.5

Sur une version antérieure à 3.12, un simple assignement fait aussi l'affaire : Vecteur = list[float].

Les annotations ne servent vraiment que si un outil les contrôle. mypy est le vérificateur de type de référence : il analyse le code sans l'exécuter et signale les incompatibilités.

Fenêtre de terminal
pip install mypy
mypy mon_projet/

Sur un fichier où une variable reçoit le mauvais type, mypy le détecte avant l'exécution :

def double(x: int) -> int:
return x * 2
resultat: str = double(21) # bug : double renvoie un int
error: Incompatible types in assignment
(expression has type "int", variable has type "str") [assignment]

C'est tout l'intérêt : attraper une classe entière de bugs avant qu'ils n'atteignent la production. On intègre mypy en pre-commit et en CI/CD pour qu'il tourne à chaque commit. pyright est une alternative rapide, intégrée à Visual Studio Code.

Aller plus loin : TypedDict, Protocol et génériques

Section intitulée « Aller plus loin : TypedDict, Protocol et génériques »

Pour des besoins plus précis, le module typing fournit des outils avancés.

Un TypedDict décrit la forme attendue d'un dictionnaire, pratique pour une réponse JSON ou une configuration :

from typing import TypedDict
class Utilisateur(TypedDict):
nom: str
age: int
u: Utilisateur = {"nom": "Alice", "age": 30}

Un Protocol définit un typage structurel : n'importe quel objet possédant les bonnes méthodes est accepté, sans héritage explicite. C'est le duck typing, mais vérifié.

from typing import Protocol
class Fermable(Protocol):
def close(self) -> None: ...
def liberer(ressource: Fermable) -> None:
ressource.close() # tout objet avec close() convient

Enfin, on écrit des fonctions génériques avec la syntaxe PEP 695 (Python 3.12), sans déclarer de TypeVar :

def premier[T](elements: list[T]) -> T:
return elements[0]
premier([1, 2, 3]) # mypy sait que le résultat est un int
premier(["a", "b"]) # ... et ici un str

Adopter les type hints demande un petit effort, vite rentabilisé :

  • Moins de bugs : mypy attrape les erreurs de type avant l'exécution.
  • Meilleure autocomplétion : l'éditeur connaît les types et propose les bonnes méthodes.
  • Documentation vivante : la signature dit exactement ce que la fonction attend et renvoie.
  • Écosystème moderne : Pydantic, FastAPI, les dataclasses et SQLAlchemy 2.0 s'appuient sur les annotations pour valider, sérialiser ou générer du code.

Inutile de tout annoter d'un coup : commencez par les signatures de fonctions publiques, là où le contrat compte le plus.

  • Un type hint annote le type attendu (x: int, -> str) sans être vérifié à l'exécution.
  • La vérification se fait avec un outil externe (mypy, pyright), jamais par l'interpréteur.
  • Depuis Python 3.9, on type les collections en natif : list[int], dict[str, float].
  • Depuis Python 3.10, une valeur optionnelle s'écrit X | None (au lieu de Optional[X]).
  • Le mot-clé type (3.12) crée des alias lisibles.
  • mypy attrape les erreurs de type avant l'exécution ; on l'intègre en pre-commit et en CI.
  • TypedDict et Protocol affinent le typage des structures et des interfaces.
  • Les annotations sont la base de Pydantic, FastAPI, des dataclasses et de SQLAlchemy 2.0.

Les annotations prennent tout leur sens sur les fonctions, la POO et les outils qui s'en servent.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn