Aller au contenu

Bonnes pratiques

Martin Fowler a dit:

Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Ce qui peut se traduire par:

Tout le monde peut écrire du code qu'une machine comprend. Les bons programmeurs écrivent du code que les humains peuvent comprendre.

Écrire un texte dans une langue nécessite le respect de règles typographiques concernant notamment l'usage des majuscules, des espaces, de la ponctuation, des paragraphes, etc.

Il en est de même pour les langages de programmation. Cela permet de rendre le code plus lisible pour soit et pour les autres.

Des propositions d'améliorations concernant le langage Python sont régulièrement publiées : les Python Enhancement Proposal (PEP).

Nous nous limiterons à quelques recommandations extraites de la PEP 8 : Style Guide for Python Code.

Mise en page

  • Indentation: les blocs d'instructions sont indentés de 4 espaces
  • Longueur des lignes: une ligne doit contenir moins de 80 caractères.

Règles de nommage

Les noms de variables, fonctions ne doivent pas contenir d'accent. Les caractères autorisés sont les lettres, les chiffres et le tiret bas : _

Un nom ne peut pas commencer par un chiffre.

Un nom ne peut pas être un mot mot réservé ou celui d'un fonction de base Python. Dans un éditeur de texte, ces mots prennent une couleur particulière. Il est plus simple d'être vigilant que d'en apprendre la liste. Attention tout de même max et min sont des noms de fonctions.

Variables et fonctions

Les noms des variables et des fonctions est à écrire en lettres minuscules séparées par des tirets bas.

Constantes

Les constantes sont à écrire en majuscules séparées par des tirets bas.

Exemples

joueur1 = "Tom"
mon_compteur = 3
MAX = 99
NB_CARTES = 32
1ier_joueur = "Jules"   # Commment par un chiffre
nb-joueurs = 4          # contient un tiret
nb cartes = 56          # contient un espace

Remarque

  • Le style recommandé pour nommer les variables et les fonctions en Python est appelé snake_case;
  • Les style recommandé pour les classes d'objets en python est le CamelCase.

Espaces

Pour des questions de lissibilité d'utiliser des espaces. Voici quelques règles à suivre:

  • ;,, et : s'écrivent sans espace avant et avec une espace après;
  • Les opérateurs +,- , etc. ont une espace avant et après;
  • Lorsque l'expression comporte plusieurs opérateurs, on peut réserver l'utilisation des espaces à l'opérateur ayant la priorité la plus faible.
Exemple
somme = 0
somme = somme + 2
x = 7*x + 3

Parenthèses, accolades et crochets.

Il n'y a pas d'espace:

  • Après une parenthèse, une accolade ou un crochet ouvrant;
  • Avant une parenthèse, une accolade ou un crochet fermant;
  • Entre le nom d'une fonction la parenthèse ouvrante;
  • Entre le nom d'une liste ou d'un dictionnaire et le crochet ouvrant.
Exemple
a = (3 + 4)*(8 - 5)
f(4)
mon_tableau = [2,4,6,3,5]
mon_tableau[4] = 7
mon_dictionnaire = {'nom': 'Paul', 'specialite' : ('NSI', 'mathématiques', 'HGGSP')}
mon_dictionnaire['nom'] = 'Jean'

Les commentaires et les docstring

Afin de faciliter la relecture par soi ou un tiers il est conseillé de commenter les fonctions. Il y a deux types de commentaires: - Les docstrings: c'est la documentation d'un fonction qui permet d'utiliser cette fonction sans avoir besoin d'en lire son code. - Les commentaires: c'est la documentation du code. Ils expliquent le fonctionnement d'un partie de code.

Les commentaires

Les textes après un# sont des commentaires. Ils ne sont pas lus par l'interpréteur mais permette d'expliquer le code. Il est important d'en mettre pour pouvoir modifier un code existant.

Exemple

import random as rd
def lancer_2_des() ->  int:
    ```
    Retourne la somme  de deux dés à 6 faces
    ```
    de1 = rd.randint(1,6) # simule un dé à 6 faces
    de2 = rd.randint(1,6) # simule un autre dé à 6 faces
    tirage = de1 + de2
    return tirage
simule un dé à 6 faces et simule un autre dé à 6 faces sont des commentaires.

Retourne la somme de deux dés à 6 faces est la docstring de cette fonction.

Les docstrings

Une docstring est écrite entre triple quotes juste après l'en-tête de la fonction et indentée comme le bloc d'instruction qui la suit.

Elles contiennent une version simplifiée des spécifications de la fonction. C'est le contenu de la docstring d'une fonction qui est renvoyé lorsque l'on utilise la fonction help.

Exemple
def minimum(a:float,b:float) -> float:
    """
    Renvoie le plus petit des nombres a et b
    """
    if a < b:
        return a
    else:
        return b

Une fois ce code exécuté on peut demander de l'aide sur cette fonction:

>>> help(minimum)
Help on function minimum in module __main__:

minimum(a: float, b: float) -> float
Renvoie le plus petit des nombres a et b

Préconditions et jeu de tests

Préconditions

Lorsque l'on écrit une fonction, il faut veiller à ce que les arguments donnés soient cohérents. Par exemple, il faut être certain que l'on ne donne pas un nombre négatif pour une donnée qui représente une longueur et doit donc être positive.

Pour cela on utilise le mot-clé assert suivi de la condition que l'on veut tester.

Exemple
>>> assert 1 == 1

>>> assert 1 == 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
  • Dans le cas assert 1 == 1 comme le test est vrai, le programme continu;
  • Dans le cas assert 1 == 2 comme le test est faux, le programme affiche un message d'erreur et s'arrête. Les éventuelles instructions qui suivent ne seront pas exécutés.

On peut ajouter un message plus spécifique lors de l'erreur. La syntaxe est:

assert condition , "Un message d'erreur"

Il ne faut pas oublier la virgule entre la condition et le message d'erreur.

Exemple
>>> assert 1 + 1 == 2, "1 + 1 devrait être égal à 2 " # Ne fait rien

>>> assert "1" + "1" == 2 , "Ne pas confondre concaténation et addition" # Plante le programme
Traceback (most recent call last):
File "<input>", line 1, in <module>
AssertionError: Ne pas confondre concaténation et addition

Dans ce cas on dit que les informations en entrée doivent vérifier des préconditions. Il suffit des mettre d'utiliser le mot-clé assert dans le corps de la fonction.

Cela offre deux avantages :

  • Si lors de l'appel de la fonction vous utilisez une valeur incohérente, cela peut vous indiquer un message d'erreur spécial;
  • lorsque vous lisez le code quelque temps plus tard, vous vous rappelez immédiatement des conditions de validité de votre fonction.
Exemple

La fonction aire_rectangle prend en argument la longueur et la largeur d'un rectangle et en retourne son aire. Les longueurs doivent être positives. On peut donc dire que nous avons deux préconditions qui doivent être vérifiées : d'une part l >= 0 et d'autre part L >= 0. On obtient:

def aire_rectangle(l, L):
assert l >=0, "Le paramètre l (largeur) doit être positif ou nul."
assert L >=0, "Le paramètre L (longueur) doit être positif ou nul."
aire = l * L
return aire
Lors de l'appel de cette fonction, on obtient:
>>> aire_rectangle(5, 3)
15
>>>aire_rectangle(3, -5)
AssertionError: Le paramètre L (longeur) doit être positif ou nul.
Un message d'erreur est renvoyé lorsqu'un des arguments est aberrant.

Les jeux de tests.

En programmation , lorsqu'on souhaite décrire ce que fait une fonction, des exemples avec les résultats attendus permettent souvent de mieux comprendre ce qu'elle fait. De plus, il est important de vérifier qu'une fonction fait bien ce qui prévu. Réfléchir aux tests permet de mieux penser les différents cas que doit traiter la fonction et donc d'éviter des erreurs de programmation.

Pour tester une fonction on utilisera le mot-clé assert en dehors du corps de la fonction. Soit après celle-ci, soit à la fin du programme.

Exemple

def minutes(h, m):
    nb_minutes = m*60 + h
    return nb_minutes
assert minutes(3, 17) == 197
assert minutes(10, 32) == 632
assert minutes(0, 41) == 41
Si la fonction passe tous les test, il n'y aura aucun affichage. Par contre si l'on des tests ne passait pas une erreur serait renvoyée.

Désormais dans les énoncés, on vous fournira souvent un jeu de tests. Lorsque vous lisez l'énoncé :

  • regarder le jeu de tests pour vous aider à comprendre ce qui est demandé,
  • une fois votre fonction programmée, exécuter la cellule avec le jeu de tests pour tester votre fonction.

Attention : dans de rares cas, votre fonction peut passer les tests mais ne pas être correcte pour autant !

On pourrait aussi utiliser le module doctest. Voici un exemple d'utilisation et sa documentation.

Il existe une librairie dédiée aux tests : unittest et qui permet de tester toutes les propriétés possibles d’un objet.

Elle est un peu vaste et trop complexe pour nos objectifs aussi nous ne l’utiliserons pas.