Aller au contenu principal

TP3 - Le code qui s'explique tout seul

Objectifs
  1. Comprendre l’intérêt de rédiger une spécification avant d’écrire une fonction ;
  2. Savoir documenter correctement une fonction en décrivant son rôle, ses paramètres et sa valeur de retour ;
  3. Améliorer la lisibilité d’un programme grâce à un nommage précis et cohérent.

En programmation, écrire du code qui fonctionne n’est que la première étape.
Écrire du code que l’on comprend — et que les autres peuvent comprendre — est tout aussi essentiel.

Un bon programme doit pouvoir « s’expliquer tout seul » avec :

  • des noms de variables clairs,
  • des fonctions bien décrites,
  • une documentation précise,
  • un code qui se lit presque comme une phrase.

Ce TP a pour but de montrer comment rendre un programme lisible, compréhensible et réutilisable.
Avant même d’écrire une seule ligne de code, on apprend à décrire ce que la fonction doit faire, comment elle doit se comporter, quels paramètres elle prend, ce qu’elle renvoie… bref, à spécifier.

C’est une compétence essentielle lors de la relecture d’un programme écrit, et indispensable dans les projets de groupe.

Le nommage : rendre le code parlant

L’une des premières règles pour écrire un code lisible concerne le nommage des variables et des fonctions.
Des noms explicites permettent à un lecteur de comprendre rapidement le rôle de chaque variable et ce que fait une fonction, sans avoir à analyser le code en détail.

Exemple de nommage ambigu

def r(l,n):
b = False
i = 0
while i < len(l) and b == False:
if l[i] == n :
b = True
else :
i+=1
return b

⚠️ Problème : les identifiants (r, l, n, b, i) n’indiquent rien. Il faut deviner leur rôle, ce qui rend le code difficile à lire et à maintenir.

Version avec un nommage explicite

def recherche(liste, nombre):
nombre_trouve = False
indice = 0
while indice < len(liste) and nombre_trouve == False:
if liste[indice] == nombre :
nombre_trouve = True
else:
indice+=1
return nombre_trouve

Dans cette version :

  • liste décrit clairement la liste de valeurs à parcourir.
  • nombre indique ce que l’on cherche.
  • nombre_trouve est un booléen qui indique si le nombre a été trouvé.
  • indice représente la position actuelle dans la liste.
À vous de jouer

On donne le programme suivant :

def ind(n,l):
t = []
for i in range(len(l)):
if l[i] == n :
t.append(i)
return t
  1. Décrire en quelques phrases ce que fait la fonction.
  2. Renommer la fonction et ses variables pour que chaque nom reflète clairement son rôle.

⚠️ Astuce : un bon nom de fonction décrit l’action principale, et un bon nom de variable décrit le contenu ou le rôle de la variable.

Spécification et documentation : décrire avant de coder

Avant d’écrire une fonction, il est essentiel de savoir exactement ce qu’elle doit faire.

Spécification

Elle décrit le comportement attendu d’une fonction, les paramètres qu’elle prend, leur type, le résultat qu’elle renvoie et éventuellement les contraintes à respecter.

Documentation

Elle consiste à formaliser cette spécification dans le code, pour que la fonction soit lisible, compréhensible et réutilisable.

Objectif final

Écrire du code qui s’explique presque tout seul grâce à un nommage clair et une documentation précise.

La spécification

Avant de coder, on décrit la fonction :

  • Rôle : que doit faire la fonction ?
  • Paramètres : combien ? quels types ? que représentent-ils ?
  • Résultat : type et signification
  • Contraintes éventuelles : taille des listes, valeurs possibles, etc.

Exemple :

On veut créer une fonction qui transforme une liste d’entiers en une chaîne de caractères.

Spécification écrite avant le code :

  • Nom : affichage
  • Paramètre : liste (type list[int])
  • Résultat : str
  • Description : concaténer les entiers pour former une chaîne de caractères

La documentation en Python (docstring)

Pour formaliser la spécification dans le code, on utilise une docstring :

def affichage(liste: list[int]) -> str:
"""
Transforme une liste d'entiers en une chaîne de caractères.

Args:
liste (list[int]): liste d’entiers à convertir.

Returns:
str: la chaîne de caractères contenant tous les entiers.
"""
chaine = ''
for element in liste:
chaine += str(element)
return chaine

La docstring reprend exactement la spécification rédigée avant le code.

Docstring
  • On précise pour les paramètres le type à l'aide du symbole : ;
  • On précise le type en sortie avec -> ;
  • On indique les informations de la spécification sous la forme d'un commentaire multilignes en début de fonction, avec le symbole """.

Pourquoi documenter ?

Documenter vos fonctions permet de :

  • Écrire : clarifier les idées et définir un objectif précis avant de coder.
  • Lire : comprendre rapidement ce que fait une fonction, même si elle est complexe.
  • Collaborer : faciliter le travail en équipe en rendant le code compréhensible pour les autres.
Lire la documentation

Dans la console python, la commande help(fonction) permet d'afficher la documentation associée à la fonction précisée.

Exercices

Pour chaque exercice

Pour chaque question, vous allez devoir :

  • Rédiger la spécification de la fonction avant de coder (décrire le rôle, les paramètres, le type de retour et les contraintes éventuelles) ;
  • Écrire la docstring correspondant à cette spécification ;
  • Implémenter et tester la fonction sur plusieurs cas représentatifs (normaux et limites).
  1. Fonction pair_impair(liste) prenant une liste d'entiers en paramètre, et retourne 2 listes comportant dans l'une les entiers pairs de la liste en paramètre, dans l'autre les entiers impairs.
  2. Fonction nb_zero(nombre) prenant un entier en paramètre, et compte le nombre de 0 présents dans cet entier. On pourra convertir en chaine de caractères.

Sur le réseau social TocToc, les utilisateurs peuvent "liker" les vidéos d'autres utilisateurs. Ainsi, chaque utilisateur possède un nombre de "like". On représente les utilisateurs et leurs likes avec un dictionnaire, dont les clés sont les utilisateurs, et les valeurs leur nombre de likes.

  1. Écrire une fonction premier_TocToc(donnees) prenant un dictionnaire en paramètre, cherche l'utilisateur de ce dictionnaire ayant le plus de likes, et retourne un tuple comprenant en premier élément l'utilisateur, et en second élément son nombre de likes.

On va s'intéresser ici à la codification des couleurs en hexadécimal. Plus précisément, nous allons convertir un code hexadécimal ("F03B5D" par exemple) en un tuple (rouge, vert, bleu) :

    1. Écrire une fonction lettre_en_chiffre(lettre) qui prend une lettre hexadécimale en paramètre, et la convertie en sa valeur décimale ("0" = 0, "1" = 1, ... "A" = 10, ... "F" = 15). On utilisera un dictionnaire dans la fonction. La fonction retournera la valeur décimale.
    2. Écrire une fonction hexa_dec(lettre1,lettre2) qui prend 2 lettres hexadécimales en paramètre, et calcule la valeur décimale suivant la formule de conversion (pour rappel : F5 = 15 ∗ 161 + 5 ∗ 160). La fonction retournera la valeur décimale. On utilisera la fonction écrite précédemment.
    3. Écrire une fonction hexa_vers_rvb(chaine) prenant une chaîne de caractères comprenant 6 caractères maximum, et retournant un tuple de 3 valeurs. Chacune des valeurs du tuple sera la conversion de 2 caractères de la chaîne, convertis grâce à la fonction précédente.