Utiliser des classes comme dépendances¶
🌐 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.
Avant d'aller plus loin dans le système d'Injection de dépendances, mettons à niveau l'exemple précédent.
Un dict de l'exemple précédent¶
Dans l'exemple précédent, nous renvoyions un dict depuis notre dépendance (« dependable ») :
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
Mais nous recevons alors un dict dans le paramètre commons de la fonction de chemin d'accès.
Et les éditeurs ne peuvent pas apporter beaucoup d'assistance (comme l'autocomplétion) pour les dict, car ils ne peuvent pas connaître leurs clés ni les types de valeurs.
Nous pouvons faire mieux ...
Ce qui fait d'un objet une dépendance¶
Jusqu'à présent, vous avez vu des dépendances déclarées sous forme de fonctions.
Mais ce n'est pas la seule manière de déclarer des dépendances (même si c'est probablement la plus courante).
L'élément clé est qu'une dépendance doit être un « callable ».
Un « callable » en Python est tout ce que Python peut « appeler » comme une fonction.
Ainsi, si vous avez un objet something (qui n'est peut‑être pas une fonction) et que vous pouvez « l'appeler » (l'exécuter) comme :
something()
ou
something(some_argument, some_keyword_argument="foo")
alors c'est un « callable ».
Utiliser des classes comme dépendances¶
Vous remarquerez que pour créer une instance d'une classe Python, vous utilisez la même syntaxe.
Par exemple :
class Cat:
def __init__(self, name: str):
self.name = name
fluffy = Cat(name="Mr Fluffy")
Dans ce cas, fluffy est une instance de la classe Cat.
Et pour créer fluffy, vous « appelez » Cat.
Donc, une classe Python est aussi un « callable ».
Ainsi, avec FastAPI, vous pouvez utiliser une classe Python comme dépendance.
Ce que FastAPI vérifie réellement, c'est qu'il s'agit d'un « callable » (fonction, classe ou autre) et des paramètres qui y sont définis.
Si vous passez un « callable » comme dépendance dans FastAPI, il en analysera les paramètres et les traitera de la même manière que les paramètres d'une fonction de chemin d'accès. Y compris les sous‑dépendances.
Cela s'applique également aux callables sans aucun paramètre. Comme ce serait le cas pour des fonctions de chemin d'accès sans paramètres.
Nous pouvons alors remplacer la dépendance « dependable » common_parameters ci‑dessus par la classe CommonQueryParams :
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
Faites attention à la méthode __init__ utilisée pour créer l'instance de la classe :
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
... il a les mêmes paramètres que notre précédent common_parameters :
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: Annotated[dict, Depends(common_parameters)]):
return commons
@app.get("/users/")
async def read_users(commons: Annotated[dict, Depends(common_parameters)]):
return commons
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
async def common_parameters(q: str | None = None, skip: int = 0, limit: int = 100):
return {"q": q, "skip": skip, "limit": limit}
@app.get("/items/")
async def read_items(commons: dict = Depends(common_parameters)):
return commons
@app.get("/users/")
async def read_users(commons: dict = Depends(common_parameters)):
return commons
Ce sont ces paramètres que FastAPI utilisera pour « résoudre » la dépendance.
Dans les deux cas, il y aura :
- Un paramètre de requête optionnel
qqui est unstr. - Un paramètre de requête
skipqui est unint, avec une valeur par défaut de0. - Un paramètre de requête
limitqui est unint, avec une valeur par défaut de100.
Dans les deux cas, les données seront converties, validées, documentées dans le schéma OpenAPI, etc.
Utiliser¶
Vous pouvez maintenant déclarer votre dépendance en utilisant cette classe.
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
FastAPI appelle la classe CommonQueryParams. Cela crée une « instance » de cette classe et l'instance sera passée comme paramètre commons à votre fonction.
Annotation de type vs Depends¶
Remarquez que nous écrivons CommonQueryParams deux fois dans le code ci‑dessus :
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
Astuce
Privilégiez la version avec Annotated si possible.
commons: CommonQueryParams = Depends(CommonQueryParams)
Le dernier CommonQueryParams, dans :
... Depends(CommonQueryParams)
... est ce que FastAPI utilisera réellement pour savoir quelle est la dépendance.
C'est à partir de celui‑ci que FastAPI extraira les paramètres déclarés et c'est ce que FastAPI appellera effectivement.
Dans ce cas, le premier CommonQueryParams, dans :
commons: Annotated[CommonQueryParams, ...
Astuce
Privilégiez la version avec Annotated si possible.
commons: CommonQueryParams ...
... n'a aucune signification particulière pour FastAPI. FastAPI ne l'utilisera pas pour la conversion des données, la validation, etc. (car il utilise Depends(CommonQueryParams) pour cela).
Vous pourriez en fait écrire simplement :
commons: Annotated[Any, Depends(CommonQueryParams)]
Astuce
Privilégiez la version avec Annotated si possible.
commons = Depends(CommonQueryParams)
... comme dans :
from typing import Annotated, Any
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons=Depends(CommonQueryParams)):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
Mais il est recommandé de déclarer le type ; ainsi, votre éditeur saura ce qui sera passé comme paramètre commons, et pourra vous aider avec l'autocomplétion, les vérifications de type, etc. :

Raccourci¶
Mais vous voyez qu'il y a ici de la duplication de code : nous écrivons CommonQueryParams deux fois :
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
Astuce
Privilégiez la version avec Annotated si possible.
commons: CommonQueryParams = Depends(CommonQueryParams)
FastAPI fournit un raccourci pour ces cas, lorsque la dépendance est spécifiquement une classe que FastAPI va « appeler » pour créer une instance de la classe elle‑même.
Pour ces cas précis, vous pouvez faire ce qui suit :
Au lieu d'écrire :
commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]
Astuce
Privilégiez la version avec Annotated si possible.
commons: CommonQueryParams = Depends(CommonQueryParams)
... vous écrivez :
commons: Annotated[CommonQueryParams, Depends()]
Astuce
Privilégiez la version avec Annotated si possible.
commons: CommonQueryParams = Depends()
Vous déclarez la dépendance comme type du paramètre et vous utilisez Depends() sans aucun paramètre, au lieu d'avoir à réécrire la classe entière à l'intérieur de Depends(CommonQueryParams).
Le même exemple ressemblerait alors à ceci :
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import Depends, FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
@app.get("/items/")
async def read_items(commons: CommonQueryParams = Depends()):
response = {}
if commons.q:
response.update({"q": commons.q})
items = fake_items_db[commons.skip : commons.skip + commons.limit]
response.update({"items": items})
return response
... et FastAPI saura quoi faire.
Astuce
Si cela vous semble plus déroutant qu'utile, ignorez‑le, vous n'en avez pas besoin.
Ce n'est qu'un raccourci. Parce que FastAPI tient à vous aider à minimiser la duplication de code.