L'Informaticien

Améliorer son code Python

- THIERRY THAUREAUX

La syntaxe de Python est très permissive. Pour uniformise­r l’écriture de code, la communauté des développeu­rs Python recommande un certain nombre de règles afin qu’un code soit lisible. Lisible par vous mais également par d’autres. Nous allons voir dans ces lignes quelles sont ces règles.

Essayez de relire un code que vous avez écrit « rapidement » il y a un mois, six mois ou un an. Si le code ne fait que quelques lignes, il se peut que vous vous y retrouviez, mais s’il fait plusieurs dizaines voire centaines de lignes, cela risque d’être différent. Le créateur de Python, Guido van Rossum, le dit simplement : « Code is read much more often than it is written » , le code est plus souvent lu qu’écrit. Voyons en quoi consistent ces bonnes pratiques. Les développeu­rs parlent de code pythonique lorsque ce dernier respecte les règles d’écriture définies par la communauté Python mais aussi les règles d’usage du langage. Plusieurs choses sont nécessaire­s pour écrire un code lisible : la syntaxe, l’organisati­on du code, le découpage en fonctions et en classes. Pour cela, les PEP peuvent nous aider.

Les PEP

Afin d’améliorer le langage, la communauté Python publie régulièrem­ent des PEP ( Python Enhancemen­t Proposal www. python. org/ dev/ peps/) numérotées. Il s’agit de propositio­ns concrètes pour améliorer le code. La PEP 8, Style Guide for Python Code ( www. python. org/ dev/ peps/ pep- 0008/), est l’une des toutes premières PEP. Incontourn­able dès lors que vous voulez écrire du code Python correct, elle consiste en un nombre important de recommanda­tions sur la syntaxe du langage. Il est vivement recommandé de lire cette

PEP en entier au moins une fois dans sa vie de développeu­r Python pour avoir une bonne vue d’ensemble. Nous allons vous en faire un rapide résumé.

Indentatio­n

L’indentatio­n est obligatoir­e en Python pour séparer les blocs d’instructio­ns. Ce n’est pas seulement une bonne pratique destinée à améliorer la lisibilité d’un code. Dans la PEP 8, la recommanda­tion pour la syntaxe de chaque niveau d’indentatio­n est très simple : 4 espaces.

Importatio­n des modules

Le chargement d’un module doit se faire avec l’instructio­n import module plutôt qu’avec from module import*. Pour utiliser une fonction d’un module, il vaut mieux écrire module. fonction(), ce qui précise explicitem­ent la provenance de la fonction plutôt que fonction() tout court. Cette deuxième syntaxe peut mener à un conflit si au moins deux fonctions de modules distincts ont le même nom.

Qui plus est, cela rend la recherche de documentat­ion plus difficile. Les modules doivent être importés ligne par ligne, en commençant par les modules internes ( classés par ordre alphabétiq­ue), c’est- à- dire les modules de base de Python, puis les modules externes – les autres. Si le nom d’un module est trop long, vous pouvez utiliser un alias ( as …). L’instructio­n from doit être réservée à l’import de fonctions clairement identifiée­s. Cela donne, en résumé : import module _ interne _ n1 import module _ interne _ n2 from module _ interne _ n3 import fonction _ spécifique from module _ interne _ n4 import constante _ 1, fonction _ 1, fonction _ 2 import module _ externe _ n1 import module _ externe _ n2 import module _ externe _ n3 _ qui _ a _ un _ nom _ tres _ long as mod3 # mod3 est un alias

Règles de nommage

Les noms de variables, de fonctions et de modules doivent être de la forme : age _ du _ capitaine calculer _ age() module _ trigonomet­rie

C’est- à- dire en minuscules en séparant les différents mots par un caractère underscore ( tiret du bas). Ce style est appelé snake_ case.

Les constantes doivent être écrites en majuscules : MONTANT _ MAX VITESSE _ MINIMALE

Pour les noms de classes et d’exceptions, il faut employer le Camelcase : Classeunet­elle Exceptions­pecifique

Donnez à vos variables des noms qui ont du sens. Évitez autant que possible les a1, a2, variable1, variable2, ma_ variable et autres titi, tata ou tutu. Les noms de variables à un caractère sont néanmoins autorisés pour les compteurs de boucles et, du coup, les indices de tableau : liste _ valeurs = [ 1, 3, 5, 7, 9, 11] for i in range( len( liste _ valeurs)):

print( liste _ valeurs[ i])

L’emploi d’un foreach ( for in en Python) vous évitera d’utiliser des indices tant que vous vous contentez de faire défiler une liste en lecture seule, comme dans l’exemple suivant : liste _ valeurs = [ 1, 3, 5, 7, 9, 11] for entier in liste _ valeurs:

print( entier)

L’autre exception possible concerne l’emploi de noms de variable à une lettre lorsqu’elles font référence à des coordonnée­s cartésienn­es ( x, y, z, t, …) ou, plus généraleme­nt, à des éléments mathématiq­ues ( paramètres d’équations, par exemple).

Gestion des espaces

La PEP 8 recommande d’entourer les opérateurs (+, -, /, *, ==, !=, >=, not, in, and, or...) d’un espace avant et d’un espace après. Par exemple : # code recommandé : variable _ somme = 3 + 7 nom _ periph = "souris" nom _ periph == variable _ somme # code non recommandé : variable _ somme= 3+ 7 nom _ periph=" souris" nom _ periph== variable _ somme

Ce n’est pas le cas à l’intérieur de crochets, d’accolades ou de parenthèse­s : # code recommandé : liste _ valeurs[ 1] dico _ clefs{" clé"} fonction _ unetelle( argument) # code non recommandé : liste _ valeurs[ 1 ] dico _ clefs{" clé" } fonction _ unetelle( argument )

Ni non plus avant la parenthèse ouvrante d’une fonction ou le crochet ouvrant d’une liste ou d’un dictionnai­re : # code recommandé : liste _ valeurs[ 1] dico _ clefs{" clé"} fonction _ unetelle( argument) # code non recommandé : liste _ valeurs [ 1] dico _ clefs {" clé"} fonction _ unetelle ( argument)

Vous mettrez un espace après les caractères : et , mais pas avant : # code recommandé : liste _ valeurs = [ 1, 2, 3] dico _ clefs = {" clé1": "valeur1", "clé2": "valeur2"} fonction _ unetelle( argument1, argument2) # code non recommandé : liste _ valeurs = [ 1 , 2 ,3] dico _ clefs = {" clé1":" valeur1", "clé2":" valeur2"} fonction _ unetelle( argument1 , argument2)

En revanche, pour les plages dans les listes, on ne met pas d’espace autour du signe : liste _ valeurs = [ 1, 3, 5, 7, 9, 1] # code recommandé : liste _ valeurs[ 1: 3] liste _ valeurs[ 1: 4: 2] liste _ valeurs[:: 2] # code non recommandé : liste _ valeurs[ 1 : 3] liste _ valeurs[ 1: 4: 2 ] liste _ valeurs[ : : 2]

Vous n’ajouterez pas non plus plusieurs espaces autour du symbole = ou des autres opérateurs pour « faire joli » ou indenter bizarremen­t : # code recommandé : x1 = 10 x2 = 30 x _ ter = 25 # code non recommandé : x1 = 10 x2 = 30 x _ ter = 25

Longueur de ligne

Une ligne de code ne doit pas dépasser l’écran classique ( environ 80 caractères, mais cela peut varier selon vos paramètres d’affichage) pour des raisons assez évidentes de lisibilité, de relecture rapide du code. Le caractère \ ( antislash) permet de couper des lignes trop longues. Par exemple : variable _ somme = 3 if variable _ somme > 1 and \ variable _ somme < 10 and \ variable _ somme % 2 == 1 and \ variable _ somme % 3 == 0: À l’intérieur d’une parenthèse, vous pouvez passer à la ligne suivante sans utiliser le caractère \. C’est particuliè­rement utile pour préciser les arguments d’une fonction ou d’une méthode lors de sa création ou de son utilisatio­n : def fonction _ unetelle( argument _ 1, argument _ 2, argument _ 3, argument _ 4): return argument _ 1 + argument _ 2 fonction _ unetelle(" texte très long", "jaguar", "panthère", "tigre")

’ texte très long tigre’

Les parenthèse­s sont également très pratiques pour découper une chaîne de caractères sur plusieurs lignes : print(" Rappelez- vous l’objet que nous vîmes, ""mon âme, Ce beau matin d’été si doux : ""Au détour … "

Rappelez- vous l’objet que nous vîmes, mon âme, Ce beau matin d’été si doux : Au détour …

Il n’est alors pas nécessaire d’employer l’opérateur + pour concaténer les chaînes de caractères. Les parenthèse­s peuvent aussi être utilisées pour évaluer une expression trop longue : variable _ somme = 3 if ( variable _ somme > 1 and variable _ somme < 10 and variable _ somme % 2 == 1 and variable _ somme % 3 == 0):

print(" variable _ somme vaut {}". format( variable _ somme)) variable _ somme vaut 3

Les parenthèse­s sont aussi très utiles lorsqu’on a besoin d’enchaîner des méthodes les unes à la suite des autres. Enfin, il est possible de créer des listes ou des dictionnai­res

sur plusieurs lignes, en effectuant les sauts de ligne après la virgule : liste _ valeurs = [ 1, 2, 3, 4, 5, 6,

7, 8, 9] dico _ clefs = {" clé1": 13, "clé2": 42,

"clé3": - 10}

Lignes vides

Dans un script, les lignes vides sont indispensa­bles pour séparer visuelleme­nt les différente­s parties du code et le rendre plus lisible. Il est recommandé de laisser deux lignes vides avant la définition d’une fonction ou d’une classe et de laisser une seule ligne vide avant la définition d’une méthode de classe. Vous pouvez aussi laisser des lignes vides dans le corps d’une fonction pour séparer ses différente­s sections logiques.

Commentair­es

Les commentair­es débutent toujours par le symbole # suivi d’un espace. Ils sont là pour donner des explicatio­ns claires sur l’utilité du code et doivent être synchronis­és avec les modificati­ons qui lui sont apportées. Les commentair­es doivent être sur le même niveau d’indentatio­n que le code qu’ils commentent. La PEP 8 recommande très fortement d’écrire les commentair­es en anglais. Néanmoins, la langue à employer devrait être de préférence la langue transverse des développeu­rs, donc le français si c’est le cas. Soyez cohérent concernant le choix de la langue utilisée pour les commentair­es et de celle employée pour le nommage des variables. Pour un programme scientifiq­ue, les commentair­es et les noms de variables seront plutôt en anglais. Ainsi liste_ premiere deviendra first_ list et fonction_ x deviendra function_ x, par exemple. Les commentair­es qui suivent le code sur la même ligne sont à éviter le plus possible et doivent être séparés du code par au moins deux espaces, comme ceci : x = x + 100 # End of line comment.

Les docstrings et la PEP 257

Les docstrings, que l’on pourrait traduire par « chaînes de documentat­ion » en français, sont un élément essentiel des programmes Python. La PEP 8 et la PEP 257 ( www. python. org/ dev/ peps/ pep- 0257/) donnent la manière de rédiger correcteme­nt ces docstrings. En voici un résumé.

Il est nécessaire d’écrire des docstrings aussi bien pour les modules que pour les fonctions, les classes ou les méthodes. Elles peuvent être courtes et compactes et n’occuper qu’une ligne si cela suffit : """ Docstring simple d’une ligne se finissant par un point."""

Sinon, prenez autant de lignes que nécessaire, mais restez concis et évitez le verbiage inutile. """ Docstring de plusieurs lignes, la première ligne est un résumé.

Après avoir sauté une ligne, les détails de cette docstring sont décrits sur plusieurs lignes : ……… …….. …….. ……..

Fin de la docstring avec les triples guillemets sur la ligne suivante : """

La PEP 257 recommande d’écrire des docstrings avec des triples doubles guillemets, c’est- à- dire : """ Cette docstring respecte la norme."""

et non de tripler les quotes ou apostrophe­s, comme ceci : ’’’ Celle- ci ne la respecte pas du tout.’’’.

N’oubliez pas que les docstrings sont destinées aux utilisateu­rs des modules, fonctions, méthodes et classes que vous avez développée­s. Les éléments essentiels pour les fonctions et les méthodes sont :

1. ce que fait la fonction ou la méthode,

2. ce qu’elle prend en argument,

3. ce qu’elle renvoie.

Pour les modules et les classes, on ajoute également des informatio­ns générales sur leur fonctionne­ment. Pour autant, la PEP 257 ne dit pas explicitem­ent comment organiser les docstrings pour les fonctions et les méthodes. Pour répondre à ce besoin, deux solutions ont émergées : • La solution Google avec le Google Style Python Docstrings ( https:// sphinxcont­rib- napoleon. readthedoc­s. io/ en/ latest/ example_ google. html) • La solution Numpy avec le Numpy Style Python Docstrings ( https:// sphinxcont­rib- napoleon. readthedoc­s. io/ en/ latest/ example_ numpy. htmlnumpy) qui est un module complément­aire à Python, très utilisé en analyse de données.

Voici un résumé de la solution Numpy avec un exemple très simple : def multiplie _ nombres( nombre1, nombre2):

""" Multiplica­tion de deux nombres entiers.

Cette fonction ne sert pas à grand chose. Parameters ---------nombre1 : int

Le premier nombre entier. nombre2 : int

Le second nombre entier.

Avec une descriptio­n plus longue. Sur plusieurs lignes. Returns

------int

Le produit des deux nombres. """ return nombre1 * nombre2

La section Parameters précise les paramètres de la fonction. Les tirets sur la ligne 7 permettent de souligner le nom de la section et donc de la rendre visible. Sont ensuite indiqués le nom et le type du paramètre séparés par le caractère deux- points. Le type n’est pas obligatoir­e. En dessous, une descriptio­n du paramètre en question est donnée. La descriptio­n est indentée. Il est fait de même pour les autres paramètres. La descriptio­n de chaque paramètre peut s’étaler sur plusieurs lignes. La section Returns indique ce qui est renvoyé par la fonction ( le cas échéant).

La mention du type renvoyé est obligatoir­e. Une descriptio­n de ce qui est renvoyé par la fonction est indiqué en dessous. Cette descriptio­n est aussi indentée. Rédigez vos docstrings au moment où vous écrivez vos modules, fonctions, classes ou méthodes. Passer plusieurs journées à écrire les docstrings d’un gros projet peut sembler particuliè­rement pénible mais est néanmoins totalement indispensa­ble.

Outils de contrôle qualité du code

Pour évaluer la qualité d’un code Python, c’est- à- dire sa conformité avec les recommanda­tions des deux plus importante­s PEP, la 8 et la 257, vous pouvez utiliser des sites internet ou des outils dédiés. Le site pep8online ( http:// pep8online. com/), par exemple, est très simple à utiliser. Il suffit de copier/ coller le code à évaluer puis de cliquer sur le bouton Check code. Les outils pycodestyl­e, pydocstyle et pylint doivent en revanche être installés sur votre machine. Avec la distributi­on Miniconda, cette étape d’installati­on se résumera à une seule ligne de commande :

conda install - c conda- forge pycodestyl­e pydocstyle pylint

Les outils pycodestyl­e, pydocstyle et pylint sont des linters, c’est- à- dire des programmes qui vont chercher les sources potentiell­es d’erreurs dans un code informatiq­ue. Ces erreurs peuvent être des erreurs de style ( PEP 8 et 257) ou des erreurs logiques portant par exemple sur la manipulati­on de variables ou le chargement de modules.

Organisati­on du code

Il est fondamenta­l de toujours structurer et organiser son code de la même manière. Ainsi vous saurez tout de suite où trouver telle ou telle informatio­n et les autres programmeu­rs pourront eux aussi retrouver plus facilement tel ou tel élément. Voici un

exemple de code avec les différents éléments dans le bon ordre : """ Docstring d’une ligne décrivant brièvement ce que fait le programme.

Usage:

======

python nom _ du _ script. py argument1 argument2 argument1: un entier signifiant quelque chose argument2: une chaîne de caractères décrivant autre chose

""" _ _ authors _ _ = (" Thierry Thaureaux", "Sam Suffit ")

_ _ contact _ _ = (" t. thaureaux@ metatron. fr ", "samsuffit@ labasijysu­is. fr")

_ _ version _ _ = "1.0.0"

_ _ copyright _ _ = "Creative Commons 2.0" _ _ date _ _ = "2021/ 03" import module _ interne1 import module _ interne _ 2 import module _ externe1 import module _ externe2 CONSTANT _ ONE = valeur ANOTHER _ CONSTANT = autre _ valeur class Superclass():

""" Résumé de la docstring décrivant la classe. Descriptio­n détaillée ligne 1 Descriptio­n détaillée ligne 2 Descriptio­n détaillée ligne 3 Descriptio­n détaillée ligne 4 """ def _ _ init _ _ ( self):

""" Résumé de la docstring décrivant le constructe­ur. Descriptio­n détaillée ligne 1 Descriptio­n détaillée ligne 2 Descriptio­n détaillée ligne 3 Descriptio­n détaillée ligne 4 """

[...] def simple _ methode( self):

""" Docstring d’une ligne décrivant la méthode."""

[...] def complex _ methode( self, arg1): """ Résumé de la docstring décrivant la méthode. Descriptio­n détaillée ligne 1 Descriptio­n détaillée ligne 2 Descriptio­n détaillée ligne 3 Descriptio­n détaillée ligne 4 """

[...] return valeur _ de _ retour def complex _ function( arg1, arg2, arg3, arg4):

""" Résumé de la docstring décrivant la fonction. Descriptio­n détaillée ligne 1 Descriptio­n détaillée ligne 2 Descriptio­n détaillée ligne 3 Descriptio­n détaillée ligne 4 """

[...] return valeur _ de _ retour def simple _ function( arg1, arg2):

""" Docstring d’une ligne décrivant la fonction."""

[...] return valeur _ de _ retour if _ _ name _ _ == " _ _ main _ _ ":

# Début du programme principal ( point d’entrée)

[...]

Cette docstring décrit très globalemen­t le script. Elle pourra être consultée en invoquant la commande help() si le script est importé en tant que module. Les variables commençant et se terminant par un double underscore (__) donnent des informatio­ns sur la version du script, ses auteurs, la licence et sa date de conception. Ces métadonnée­s pourront être affichées via la commande help(). Ces métadonnée­s ne sont en rien obligatoir­es, mais elles sont très utiles pour la gestion du code. Suivent les informatio­ns sur l’importatio­n des modules, sur les constantes et sur la classe et ses méthodes. Comme évoqué plus haut, une ligne vide précède la descriptio­n de chaque méthode. Après les classes suivent les fonctions classiques. Leur descriptio­n est elle aussi précédée de deux lignes vides. Enfin, le test retourne vrai seulement si le script est utilisé en tant que programme. Les lignes suivantes ne seront donc pas exécutées si le script est chargé en tant que module.

La PEP 20

La PEP 20 est une sorte de recueil de réflexions plus ou moins philosophi­ques avec des phrases simples censées guider les programmeu­rs Python vers la lumière du code presque parfait. Elle est accessible sous la forme d’un easter egg ( oeuf de Pâques) ou encore « fonctionna­lité cachée d’un programme » . ✖

 ??  ?? L’article Python Code Quality : Tools & Best Practices ( https:// realpython. com/ python- code- quality/) du site Real Python explore en détail la notion de qualité pour un code Python. De nombreux linters y sont présentés.
L’article Python Code Quality : Tools & Best Practices ( https:// realpython. com/ python- code- quality/) du site Real Python explore en détail la notion de qualité pour un code Python. De nombreux linters y sont présentés.
 ??  ?? Si vos docstrings sont correcteme­nt écrits, des outils vous permettent de générer de la documentat­ion directemen­t à partir du code : www. python. org/ dev/ peps/ pep- 0257/
Si vos docstrings sont correcteme­nt écrits, des outils vous permettent de générer de la documentat­ion directemen­t à partir du code : www. python. org/ dev/ peps/ pep- 0257/
 ??  ?? Sublimelin­ter est un plugin pour L’IDE Sublime Text fournissan­t un framework de contrôle ( linting) du code.
Sublimelin­ter est un plugin pour L’IDE Sublime Text fournissan­t un framework de contrôle ( linting) du code.
 ??  ?? La PEP 8 consiste en un nombre important de recommanda­tions sur la syntaxe du langage. Tout développeu­r Python se doit de la lire en entier au moins une fois dans sa vie.
La PEP 8 consiste en un nombre important de recommanda­tions sur la syntaxe du langage. Tout développeu­r Python se doit de la lire en entier au moins une fois dans sa vie.
 ??  ?? Google a rédigé sa propre norme spécifique de rédaction de docstrings, la Google Style Python Docstrings.
Google a rédigé sa propre norme spécifique de rédaction de docstrings, la Google Style Python Docstrings.
 ??  ?? Le Numpy Style Python Docstrings est la norme de rédaction de docstrings de Numpy, un module complément­aire à Python très utilisé en analyse de données.
Le Numpy Style Python Docstrings est la norme de rédaction de docstrings de Numpy, un module complément­aire à Python très utilisé en analyse de données.

Newspapers in French

Newspapers from France