Licence CC BY-NC-ND, Thierry Parmentelat & Arnaud Legout
from IPython.display import HTML
HTML(filename="_static/style.html")
type hints#
littéralement: suggestions de typage
motivations#
le fait de pouvoir écrire du code non typé est pratique (rapidité de développement)
mais a des limitations (notamment: confusion possible sur l’utilisation des librairies)
le but avec les type hints est introduire un mécanisme optionnel pour améliorer la situation
meilleure documentation: faciliter l’accès à une nouvelle lib
analyse statique: trouver les bugs plus tôt
et plus anecdotiquement, meilleures performances
complètement optionnel#
non seulement on n’est pas obligé d’en mettre
mais même si on en met, c’est ignoré ! à run-time
# les annotations ici indiquent que
# les paramètres et le retour sont des entiers
def ajouter(x: int, y:int) -> int:
return x + y
# mais à run-time celles-ci sont ignorées !
# la preuve, je peux utiliser des chaines à la place
ajouter('abc', 'def')
'abcdef'
à quoi ça sert alors ? vérifier#
vérification statique en utilisant mypy - un outil externe
# l'analyse statique est faite par un outil externe
# ici je choisis d'utiliser mypy
%pip install mypy
Requirement already satisfied: mypy in /home/docs/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages (1.15.0)
Requirement already satisfied: typing_extensions>=4.6.0 in /home/docs/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages (from mypy) (4.12.2)
Requirement already satisfied: mypy_extensions>=1.0.0 in /home/docs/checkouts/readthedocs.org/user_builds/ue12-p24-python/envs/p24/lib/python3.12/site-packages (from mypy) (1.0.0)
Note: you may need to restart the kernel to use updated packages.
# avec ce fichier source
%cat samples/typehints.py
# on ajoute des annotations à l'objet 'ajouter'
def ajouter(x: int, y: int) -> int:
return x + y
# mais à run-time celles-ci sont ignorées !
ajouter('abc', 'def')
# on obtient ces diagnostics d'erreur sans avoir besoin d'exécuter
# ce qui signifie qu'on peut le faire AVANT même de faire les tests
!mypy samples/typehints.py
samples/typehints.py:8: error: Argument 1 to "ajouter" has incompatible type "str"; expected "int" [arg-type]
samples/typehints.py:8: error: Argument 2 to "ajouter" has incompatible type "str"; expected "int" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
à quoi ça sert alors ? documenter#
meilleure documentation !
on perd moins de temps perdu à deviner les présupposés sur les arguments
digression sur les docstrings
lorsqu’on écrit un docstring, on n’a pas besoin de répéter la signature de la fonction, du coup les types hints se retrouvent automatiquement dans la doc, comme ceci:
def ajouter(x: int, y:int) -> int:
"""
add 2 integers
"""
return x + y
help(ajouter);
Help on function ajouter in module __main__:
ajouter(x: int, y: int) -> int
add 2 integers
les variables aussi#
au départ on pense surtout à typer les paramètres, et la sortie des fonctions
mais on peut aussi typer les variables
# le type hint permet aussi de préciser les choses sur les variables
NAMES : list[str] = []
conclusion#
comme il s’agit d’un trait relativement récent (en fait ça n’est stable que depuis la 3.9),
les type hints ne sont pas massivment présents dans le code existant
toutefois c’est clairement une voie à suivre, et en tous cas c’est important que vous sachiez le lire !
souvenez-vous qu’on peut les utiliser ponctuellement
du coup pensez à l’utiliser à chaque fois que les choses deviennent ambigües
par contre, pour pouvoir faire de la vérification statique, il faut viser une couverture beaucoup plus large pour que ça apporte vraiment quelque chose
ATTENTION avec isinstance#
(avancé)
on serait tenté d’utiliser isinstance/issubclass avec les types tels qu’on vient de les définir
mais il ne faut pas le faire! je vous renvoie à ce post
il y est suggéré de disposer d’une autre builtin que isinstance
pour vérifier si une variable est acceptable pour un type
alors que isinstance se base uniquement sur l’héritage de classes
# ceci déclenche un TypeError
from typing import Union
Phone = Union[str, int]
PhoneSet = set[Phone]
try:
isinstance( {'0123456789', 98765432}, PhoneSet)
except Exception as exc:
print(f"{type(exc)} {exc}")
<class 'TypeError'> isinstance() argument 2 cannot be a parameterized generic
comment définir un type#
les classes builtin#
dans les cas simples on utilise directement les classes builtin
str,dictetc..notez qu’on peut utiliser les
[]pour fabriquer des types plus précis, par exemplelist[int]liste d’enters
tuple[str, int]un tuple à deux éléments, une chaine et un entier
dict[str, list[int]]dictionnaire dont les clés sont des chaines et les valeurs des listes d’entiers
aliases#
évidemment on utilise souvent les mêmes types dans une application;
aussi on peut se définir son type perso avec une simple affectation, comme par exemple
classes#
pour quasiment le même genre d’usage, on peut bien sûr utiliser aussi les noms de classe
à l’intérieur d’une classe
à savoir: parfois on a besoin du nom de la classe pour typer une méthode à l’intérieur de la classe
dans ce cas-là on ne peut pas faire comme ci-dessus, car à l’intérieur de la classe le nom de la classe n’est pas encore défini (il ne sera qu’une fois l’instruction
classexécutée…)pour ce genre d’usage on peut utiliser une chaine contenant le nom de la classe
quelque chose comme ceci:
le module
typing(1)#le module
typingpermet d’étendre le spectre, en introduisant des concepts additionnelscomme par exemple
Sequence,Iterable,Callablevoici quelques exemples
pour les détails, reportez-vous comme d’hab à https://docs.python.org/3/library/typing.html
le module
typing(2)#on y trouve aussi d’autres constructeurs qui peuvent être utiles, en vrac:
Anypeut être n’importe quoiUnionlorsqu’on accepte plusieurs typesOptionalpour une variable qui peut aussi êtreNoneHashablece qui peut être utilisé comme clé d’un dictionnaireet aussi
NewTypedéfinit un nom pour un type - un peu plus subtil que l’affectationTypeVarpour manipuler des types génériques (à la template C++)grâce auxquels on peut implémenter des classes génériques