Introduction aux types Python¶
🌐 Traduction par IA et humains
Cette traduction a été réalisée par une IA guidée par des humains. 🤝
Elle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖
Vous pouvez améliorer cette traduction en nous aidant à mieux guider le LLM d'IA.
Python prend en charge des « annotations de type » (aussi appelées « type hints ») facultatives.
Ces « annotations de type » sont une syntaxe spéciale qui permet de déclarer le type d'une variable.
En déclarant les types de vos variables, les éditeurs et outils peuvent vous offrir un meilleur support.
Ceci est un tutoriel rapide / rappel à propos des annotations de type Python. Il couvre uniquement le minimum nécessaire pour les utiliser avec FastAPI ... ce qui est en réalité très peu.
FastAPI est totalement basé sur ces annotations de type, elles lui donnent de nombreux avantages et bénéfices.
Mais même si vous n'utilisez jamais FastAPI, vous auriez intérêt à en apprendre un peu à leur sujet.
Remarque
Si vous êtes un expert Python, et que vous savez déjà tout sur les annotations de type, passez au chapitre suivant.
Motivation¶
Commençons par un exemple simple :
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
Exécuter ce programme affiche :
John Doe
La fonction fait ce qui suit :
- Prend un
first_nameet unlast_name. - Convertit la première lettre de chacun en majuscule avec
title(). - Concatène ces deux valeurs avec un espace au milieu.
def get_full_name(first_name, last_name):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
Modifier le code¶
C'est un programme très simple.
Mais maintenant imaginez que vous l'écriviez de zéro.
À un certain moment, vous auriez commencé la définition de la fonction, vous aviez les paramètres prêts ...
Mais ensuite vous devez appeler « cette méthode qui convertit la première lettre en majuscule ».
Était-ce upper ? Était-ce uppercase ? first_uppercase ? capitalize ?
Vous essayez alors avec l'ami de toujours des programmeurs, l'autocomplétion de l'éditeur.
Vous tapez le premier paramètre de la fonction, first_name, puis un point (.) et appuyez sur Ctrl+Espace pour déclencher l'autocomplétion.
Mais, malheureusement, vous n'obtenez rien d'utile :

Ajouter des types¶
Modifions une seule ligne de la version précédente.
Nous allons changer exactement ce fragment, les paramètres de la fonction, de :
first_name, last_name
à :
first_name: str, last_name: str
C'est tout.
Ce sont les « annotations de type » :
def get_full_name(first_name: str, last_name: str):
full_name = first_name.title() + " " + last_name.title()
return full_name
print(get_full_name("john", "doe"))
Ce n'est pas la même chose que de déclarer des valeurs par défaut, ce qui serait :
first_name="john", last_name="doe"
C'est différent.
Nous utilisons des deux-points (:), pas des signes égal (=).
Et ajouter des annotations de type ne change normalement pas ce qui se passe par rapport à ce qui se passerait sans elles.
Mais maintenant, imaginez que vous êtes à nouveau en train de créer cette fonction, mais avec des annotations de type.
Au même moment, vous essayez de déclencher l'autocomplétion avec Ctrl+Espace et vous voyez :

Avec cela, vous pouvez faire défiler en voyant les options, jusqu'à trouver celle qui « vous dit quelque chose » :

Plus de motivation¶
Regardez cette fonction, elle a déjà des annotations de type :
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + age
return name_with_age
Comme l'éditeur connaît les types des variables, vous n'obtenez pas seulement l'autocomplétion, vous obtenez aussi des vérifications d'erreurs :

Vous savez maintenant qu'il faut corriger, convertir age en chaîne avec str(age) :
def get_name_with_age(name: str, age: int):
name_with_age = name + " is this old: " + str(age)
return name_with_age
Déclarer des types¶
Vous venez de voir l'endroit principal pour déclarer des annotations de type : dans les paramètres des fonctions.
C'est aussi l'endroit principal où vous les utiliserez avec FastAPI.
Types simples¶
Vous pouvez déclarer tous les types standards de Python, pas seulement str.
Vous pouvez utiliser, par exemple :
intfloatboolbytes
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_e
🤓 Other versions and variants
def get_items(item_a: str, item_b: int, item_c: float, item_d: bool, item_e: bytes):
return item_a, item_b, item_c, item_d, item_e
Module typing¶
Pour certains cas d'utilisation supplémentaires, vous pourriez avoir besoin d'importer certains éléments depuis le module standard typing, par exemple lorsque vous voulez déclarer que quelque chose a « n'importe quel type », vous pouvez utiliser Any depuis typing :
from typing import Any
def some_function(data: Any):
print(data)
Types génériques¶
Certains types peuvent prendre des « paramètres de type » entre crochets, pour définir leurs types internes, par exemple une « liste de chaînes » se déclarerait list[str].
Ces types qui peuvent prendre des paramètres de type sont appelés des types génériques ou Generics.
Vous pouvez utiliser les mêmes types intégrés comme génériques (avec des crochets et des types à l'intérieur) :
listtuplesetdict
Liste¶
Par exemple, définissons une variable comme une list de str.
Déclarez la variable, en utilisant la même syntaxe avec deux-points (:).
Comme type, mettez list.
Comme la liste est un type qui contient des types internes, mettez-les entre crochets :
def process_items(items: list[str]):
for item in items:
print(item)
Info
Ces types internes entre crochets sont appelés « paramètres de type ».
Dans ce cas, str est le paramètre de type passé à list.
Cela signifie : « la variable items est une list, et chacun des éléments de cette liste est un str ».
En faisant cela, votre éditeur peut vous fournir de l'aide même pendant le traitement des éléments de la liste :

Sans types, c'est presque impossible à réaliser.
Remarquez que la variable item est l'un des éléments de la liste items.
Et pourtant, l'éditeur sait que c'est un str et fournit le support approprié.
Tuple et Set¶
Vous feriez la même chose pour déclarer des tuple et des set :
def process_items(items_t: tuple[int, int, str], items_s: set[bytes]):
return items_t, items_s
Cela signifie :
- La variable
items_test untupleavec 3 éléments, unint, un autreint, et unstr. - La variable
items_sest unset, et chacun de ses éléments est de typebytes.
Dict¶
Pour définir un dict, vous passez 2 paramètres de type, séparés par des virgules.
Le premier paramètre de type est pour les clés du dict.
Le second paramètre de type est pour les valeurs du dict :
def process_items(prices: dict[str, float]):
for item_name, item_price in prices.items():
print(item_name)
print(item_price)
Cela signifie :
- La variable
pricesest undict:- Les clés de ce
dictsont de typestr(disons, le nom de chaque article). - Les valeurs de ce
dictsont de typefloat(disons, le prix de chaque article).
- Les clés de ce
Union¶
Vous pouvez déclarer qu'une variable peut être plusieurs types, par exemple, un int ou un str.
Pour le définir, vous utilisez la barre verticale (|) pour séparer les deux types.
C'est ce qu'on appelle une « union », car la variable peut être n'importe quoi dans l'union de ces deux ensembles de types.
def process_item(item: int | str):
print(item)
Cela signifie que item peut être un int ou un str.
Possiblement None¶
Vous pouvez déclarer qu'une valeur peut avoir un type, comme str, mais qu'elle peut aussi être None.
def say_hi(name: str | None = None):
if name is not None:
print(f"Hey {name}!")
else:
print("Hello World")
Utiliser str | None au lieu de simplement str permettra à l'éditeur de vous aider à détecter des erreurs où vous supposeriez qu'une valeur est toujours un str, alors qu'elle pourrait en fait aussi être None.
Classes en tant que types¶
Vous pouvez aussi déclarer une classe comme type d'une variable.
Disons que vous avez une classe Person, avec un nom :
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
Vous pouvez ensuite déclarer une variable de type Person :
class Person:
def __init__(self, name: str):
self.name = name
def get_person_name(one_person: Person):
return one_person.name
Et là encore, vous obtenez tout le support de l'éditeur :

Remarquez que cela signifie « one_person est une instance de la classe Person ».
Cela ne signifie pas « one_person est la classe appelée Person ».
Modèles Pydantic¶
Pydantic est une bibliothèque Python pour effectuer de la validation de données.
Vous déclarez la « forme » de la donnée sous forme de classes avec des attributs.
Et chaque attribut a un type.
Ensuite, vous créez une instance de cette classe avec certaines valeurs et elle validera les valeurs, les convertira dans le type approprié (le cas échéant) et vous donnera un objet avec toutes les données.
Et vous obtenez tout le support de l'éditeur avec cet objet résultant.
Un exemple tiré de la documentation officielle de Pydantic :
from datetime import datetime
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str = "John Doe"
signup_ts: datetime | None = None
friends: list[int] = []
external_data = {
"id": "123",
"signup_ts": "2017-06-01 12:22",
"friends": [1, "2", b"3"],
}
user = User(**external_data)
print(user)
# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3]
print(user.id)
# > 123
Info
Pour en savoir plus à propos de Pydantic, consultez sa documentation.
FastAPI est entièrement basé sur Pydantic.
Vous verrez beaucoup plus de tout cela en pratique dans le Tutoriel - Guide utilisateur.
Annotations de type avec métadonnées¶
Python dispose également d'une fonctionnalité qui permet de mettre des métadonnées supplémentaires dans ces annotations de type en utilisant Annotated.
Vous pouvez importer Annotated depuis typing.
from typing import Annotated
def say_hello(name: Annotated[str, "this is just metadata"]) -> str:
return f"Hello {name}"
Python lui-même ne fait rien avec ce Annotated. Et pour les éditeurs et autres outils, le type est toujours str.
Mais vous pouvez utiliser cet espace dans Annotated pour fournir à FastAPI des métadonnées supplémentaires sur la façon dont vous voulez que votre application se comporte.
L'important à retenir est que le premier « paramètre de type » que vous passez à Annotated est le type réel. Le reste n'est que des métadonnées pour d'autres outils.
Pour l'instant, vous avez juste besoin de savoir que Annotated existe, et que c'est du Python standard. 😎
Plus tard, vous verrez à quel point cela peut être puissant.
Astuce
Le fait que ce soit du Python standard signifie que vous bénéficierez toujours de la meilleure expérience développeur possible dans votre éditeur, avec les outils que vous utilisez pour analyser et refactoriser votre code, etc. ✨
Et aussi que votre code sera très compatible avec de nombreux autres outils et bibliothèques Python. 🚀
Annotations de type dans FastAPI¶
FastAPI tire parti de ces annotations de type pour faire plusieurs choses.
Avec FastAPI, vous déclarez des paramètres avec des annotations de type et vous obtenez :
- Du support de l'éditeur.
- Des vérifications de types.
... et FastAPI utilise les mêmes déclarations pour :
- Définir des prérequis : à partir des paramètres de chemin de la requête, des paramètres de requête, des en-têtes, des corps, des dépendances, etc.
- Convertir des données : de la requête vers le type requis.
- Valider des données : provenant de chaque requête :
- En générant des erreurs automatiques renvoyées au client lorsque la donnée est invalide.
- Documenter l'API avec OpenAPI :
- ce qui est ensuite utilisé par les interfaces utilisateur de documentation interactive automatiques.
Tout cela peut sembler abstrait. Ne vous inquiétez pas. Vous verrez tout cela en action dans le Tutoriel - Guide utilisateur.
L'important est qu'en utilisant les types standards de Python, en un seul endroit (au lieu d'ajouter plus de classes, de décorateurs, etc.), FastAPI fera une grande partie du travail pour vous.
Info
Si vous avez déjà parcouru tout le tutoriel et êtes revenu pour en voir plus sur les types, une bonne ressource est l'« aide-mémoire » de mypy.