Coder avec les type hints : une pratique simple qui optimise votre business
Python Bonnes Pratiques

Coder avec les type hints : une pratique simple qui optimise votre business

Valentin Chab | | 8 min de lecture

Dans le monde du developpement logiciel, les petits details font de grandes differences. Adopter des bonnes pratiques comme l’utilisation des type hints en Python peut sembler un changement mineur, mais ca a un impact direct sur la qualite du code, l’efficacite de l’equipe et la scalabilite du business.

Moins d’erreurs, plus de lisibilite, une meilleure collaboration entre developpeurs : tout ca se traduit en moins de temps perdu, moins de dette technique et plus de valeur livree.

Dans cet article, on va vous presenter un outil tres utile pour corriger notre code, eviter les erreurs et garantir que quiconque viendra lire notre code apres nous ne s’arrachera pas les cheveux. C’est parti !

C’est-a-dire, type, rien

Python est un langage a typage dynamique, ce qui signifie que les variables peuvent changer de type de donnees au cours de l’execution d’un script, contrairement aux langages a typage statique ou l’on declare le type de chaque variable avant la compilation. Ca le rend plus flexible et offre plus de possibilites, mais ca le rend aussi plus sensible a certaines erreurs.

De quoi parle-t-on ? Voici une fonction appelee multi_call definie dans un fichier appele multi.py.

Fonction multi_call avec valeur par defaut

C’est une fonction tout a fait normale : elle prend deux arguments, num et alt, et alt a une valeur par defaut egale a False. Si alt est egal a True, la sortie de notre fonction sera num multiplie par 5. Si on laisse la valeur par defaut de alt, l’execution renverra num multiplie par -2.

Quand on definit un argument de fonction, si on n’explicite pas le type de donnees attendu, l’interpreteur Python identifiera qu’il s’agit d’une variable de type “Any” ; c’est-a-dire qu’il accepte n’importe quel type de donnees en entree.

Fonction multi_call sans typage

Dans le cas de cette fonction, en definissant nous-memes une valeur par defaut booleenne pour l’argument alt, Python s’attendra a un type de donnees identique, donc il accepterait True ou False mais pas 1, 3.7 ou “true”. Mais que se passe-t-il si on ne veut pas indiquer de valeurs par defaut ? Comment peut-on aider a rendre notre code plus lisible et moins sujet aux erreurs et bugs ?

Il existe des outils et bonnes pratiques qui nous aident a definir et expliciter le type de donnees que l’on assigne a chaque variable comme une couche de controle supplementaire. L’un d’eux est le type hint.

Un indice pour toi…

Quand on indique que la valeur par defaut de alt est False, l’interpreteur Python determine que c’est un argument qui prend des valeurs booleennes. alt=False est equivalent a ecrire alt: bool = False et, dans cette seconde syntaxe, on dit “l’argument alt prend des valeurs booleennes et a pour defaut la valeur False”. Dans les versions modernes de Python (3.10 et plus), on peut aussi utiliser une syntaxe plus concise avec l’operateur | pour definir des types optionnels : par exemple, alt: bool | None si on acceptait aussi des valeurs nulles.

C’est utile pour eliminer l’ambiguite et prevenir les erreurs a l’execution, et c’est quelque chose qu’on peut faire explicitement avec tous les parametres d’une fonction donnee. A partir de Python 3.9, on peut meme utiliser une syntaxe plus simple et native comme list[int] ou dict[str, float], sans avoir besoin d’importer List ou Dict depuis typing.

Observons la fonction multi_call() mise a jour avec plus d’informations :

Fonction multi_call typee

Ici, on voit clairement que le developpeur qui a ecrit cette fonction a indique que l’argument num doit prendre des valeurs entieres, une definition logique puisque ca sera ensuite multiplie par 5 ou -2 selon la condition booleenne imposee par l’argument alt. Mais en plus, on ajoute en dehors des parentheses des arguments de la fonction un -> int, qui precise le type de donnees de la sortie de notre fonction.

Ces “petits coups de pouce” qu’on donne a notre fonction s’appellent des “type hints”, des indices de types, et c’est un excellent outil pour garder notre code propre, lisible et sans bugs. Ils ont ete presentes dans le PEP 484 (Python Enhancement Proposal, un document d’information pour la communaute Python qui propose des ameliorations ou decrit de nouvelles fonctionnalites ou processus) et sont devenus une pratique courante dans tous types de developpements en Python.

L’un des avantages est de pouvoir survoler une variable avant son affectation pour que l’interpreteur nous indique a l’avance quel sera le type de la variable resultante. Ca semble evident et trivial dans une fonction simple comme celle qu’on analyse, mais dans des fonctions plus complexes ca peut nous faire gagner pas mal de temps d’analyse de code et de types de donnees.

Maintenant, si on appelle multicall et qu’on passe 7.2 pour l’argument _num, c’est-a-dire un float au lieu d’un int, la fonction s’executera quand meme. On entend deja votre frustration de l’autre cote de l’ecran. Pourquoi, si on a specifie le type avec un type hint ? Parce que les hints ne forcent pas le type de donnees que la fonction prend, ils facilitent son utilisation pour notre utilisateur. Si on voulait bloquer une execution qui ne correspond pas aux hints qu’on a donnes, il faudrait utiliser une syntaxe similaire a celle-ci qui etend notre code :

Fonction multi_call avec assert

Dans cette fonction modifiee, c’est la declaration assert qui valide le type de donnees.

Donc, on sait maintenant que les type hints sont une bonne pratique pour la lisibilite et le debogage de notre code. Il est temps de vous presenter un outil qui va nous faciliter la vie encore davantage, ainsi que celle de toute personne qui devra travailler avec ces scripts.

Qui veut la fin veut les moyens

Avant d’aller plus loin, j’aimerais faire une breve parenthese pour vous parler des linters, un composant tres utile et dans de nombreux cas crucial pour garantir la lisibilite, la qualite et le respect des standards et bonnes pratiques de notre code.

Un linter (le terme vient d’un utilitaire Unix utilise pour trouver des erreurs dans du code ecrit en C) est un outil qu’on peut integrer a notre IDE pour aider au developpement de code via la detection d’erreurs potentielles, bugs, inconsistances de style et autres problemes. Il existe des linters de differents types pour trouver des erreurs tres variees ; a chaque developpeur de trouver celui qui lui convient le mieux.

Voyons donc une bibliotheque specialement concue pour automatiser la verification des type hints : MyPy. L’idee de ce linter est qu’il incorpore des elements d’un langage a typage statique dans Python pour tester les fonctions que l’on definit dans notre code en verifiant que les types de donnees declares comme type hints correspondent aux variables appelees par la suite. Ca nous permet, sans executer les scripts, de garantir un typage coherent des variables et des sorties de nos fonctions.

L’installation se fait avec la commande !pip install, comme la plupart des bibliotheques standard.

Selectionner MyPy dans VSCode

Il est important de noter que MyPy ne fonctionne pas pour les Jupyter Notebooks (l’une des options preferees des data scientists pour prototyper des scripts), mais bien pour analyser des fichiers entiers.

Ci-dessous, on voit l’exemple de classes.py :

  • On a un init qui prend trois arguments : a, b et c, avec les types int, str et float respectivement.
  • On a parametre a a 1, b a 1 et c a “asdad” (aussi connu sous le nom de “tete sur le clavier”).
  • Le type de donnees qu’on a indique pour notre parametre a est correct ; 1 est un int. Mais b et c ont ete declares avec des types de donnees incorrects par rapport a ce qu’on a specifie comme type hint. Si on regarde de pres, quand MyPy est selectionne comme linter, dans notre affectation de A, les parametres b et c sont soulignes d’un petit trait rouge indiquant une erreur.

DataClass avec type hints et erreur

Rappelons une fois de plus que passer des parametres a nos fonctions avec des types de donnees differents de ceux indiques en type hints ne signifie pas que l’execution sera erronee. Quand on corrige les types de donnees passes en parametres pour qu’ils correspondent a ce qu’on a indique, les lignes rouges sous les arguments disparaissent.

Maintenant, voyons comment on peut analyser le fichier contenant notre classe avec MyPy.

MyPy erreurs de typage

Si on appelle le fichier multi.py qui contient multi_call (qui, soit dit en passant, se trouve dans le meme repertoire que ce notebook qu’on execute) avec la commande !mypy, on voit que dans la sortie de cette cellule la bibliotheque a immediatement detecte les inconsistances dont on parlait.

Une autre option est d’appeler directement !mypy, ce qui analysera tous les fichiers .py du repertoire.

MyPy erreurs multiples fichiers

Mais j’en veux encore…

C’est tout pour ce premier article. On a vu comment l’utilisation des type hints et d’outils comme MyPy n’ameliore pas seulement la qualite du code, mais impacte aussi l’efficacite de l’equipe, reduit les erreurs evitables et facilite la maintenance des projets en croissance. Dans des contextes ou le logiciel fait partie du coeur de metier, ecrire du code plus clair, lisible et controle n’est pas qu’une question technique, c’est une decision strategique.

Et si en plus de suggerer des types, on pouvait les valider automatiquement a l’execution ? Il existe une bibliotheque concue exactement pour ca… mais on vous en parle dans le prochain volet.


References supplementaires :

  1. PEP 484 – Type Hints
  2. Documentation officielle de MyPy
  3. Linting dans VSCode
  4. Python Typing Module
Partager

Vous avez un vrai problème technique ?

On ne vend pas de solutions génériques. Parlons de ce que vous devez résoudre.

Parlons-en