Repérer les bugs : structures
- Fiche de cours
- Quiz
- Profs en ligne
- Videos
- Application mobile
- Repérer les problèmes de nommage des variables.
- Repérer les problèmes de choix des inégalités.
- Repérer les problèmes d’utilisation des instructions conditionnelles.
- Repérer les problèmes d’utilisation des flottants.
- Ne pas donner des noms explicites aux variables peut créer de la confusion.
- Dans la mesure du possible, il faut éviter l’utilisation de flottants car leur représentation binaire n’est a priori pas exacte.
- Si un programme qui comprend des instructions conditionnelles ou des comparaisons ne fonctionne pas, il faut vérifier les opérateurs de comparaison (<, <=, >=, >, ==, !=) et si tous les cas ont été pris en compte.
- Utiliser une instruction conditionnelle en Python. (1re)
- Écrire une fonction en Python. (1re)
Lorsque l’on écrit un programme, il est courant de se tromper en changeant de nom de variable pendant l’écriture du code.
Une erreur NameError est ainsi générée.
Voici un exemple dans lequel une confusion est faite entre a et A.
Lorsque l’on écrit une fonction, une erreur
de nommage peut entrainer une autre erreur :
UnboundLocalError.
Cela signifie que Python a trouvé dans le code de
la fonction une variable non définie et
qu’elle n’est pas définie non plus
à l’extérieur de la fonction.
Voici le code d’une fonction somme(tab) dont le but est de calculer la somme des éléments du tableau tab.
Python indique ici que la variable S est appelée avant d’être définie.
En programmation comme en mathématiques, il est important de distinguer l’utilisation des inégalités strictes et des inégalités larges.
Si a et b sont des variables qui référencent des nombres :
- a < b vaut True si a est plus petit que b et si a est différent de b ; cette expression vaut False sinon.
- a <= b vaut True si a est plus petit que b ou si a est égal à b ; cette expression vaut False sinon.
Une mauvaise utilisation des inégalités peut empêcher un code de bien fonctionner.
Les deux fonctions suivantes permettent de déterminer un indice du maximum d’un tableau de nombres tab.
Fonction maximum1(tab) |
def maximum1(tab): maxi = 0 for i in range(len(tab)): if tab[i] > tab[maxi]: maxi = i return maxi |
Fonction maximum2(tab) |
def maximum2(tab): maxi = 0 for i in range(len(tab)): if tab[i] >= tab[maxi]: maxi = i return maxi |
Seul le test tab[i]
>= tab[maxi]
est différent mais à première vue,
ces deux fonctions font la même chose.
En réalité, ce n’est pas le
cas :
- maximum1([3, 2, 1, 3]) renvoie 0.
- maximum2([3, 2, 1, 3]) renvoie 3.
En programmation, l’instruction conditionnelle if est essentielle. On la retrouve partout. Il est cependant important, lorsque l’on distingue plusieurs cas avec des instructions if-elif-else, de s’assurer que tous les cas sont bien pris en compte.
On souhaite écrire une fonction maximum(a, b, c) qui prend pour arguments trois nombres a, b et c, et qui renvoie le plus grand des trois nombres.
Voici une première fonction.
Python | Explication |
def maximum(a, b, c): | On définit la fonction maximum(a, b, c). |
if a < b
and b < c: return c |
Si a est plus petit que b et si b est plus petit que c, le plus grand élément est c. |
elif a < c and c < b: return b |
Si a est plus petit que c et si c est plus petit que b, le plus grand élément est b. |
else: return a |
Sinon le plus grand élément est a. |
Cette fonction ne fait pas ce que l’on veut car, par exemple, maximum(2, 3, 1) renvoie 2.
En réalité, tous les cas ne sont pas pris en compte.
Un code correct peut être le suivant.
Python | Explication |
def maximum(a, b, c): | |
if a < b and b < c: return c |
Si a est plus petit que b et si b est plus petit que c, le plus grand élément est c. |
elif a < c and c < b: return b |
Si a est plus petit que c et si c est plus petit que b, le plus grand élément est b. |
elif b < c and c < a: return a |
Si b est plus petit que c et si c est plus petit que a, le plus grand élément est a. |
elif b < a and a < c: return c |
Si b est plus petit que a et si a est plus petit que c, le plus grand élément est c. |
elif c < b and b < a: return a |
Si c est plus petit que b et si b est plus petit que a, le plus grand élément est a. |
elif c < a and a < b: return b |
Si c est plus petit que a et si a est plus petit que b, le plus grand élément est b. |
Il y a 6 cas possibles.
En programmation, l’utilisation des nombres flottants (des nombres à virgule) est délicate.
En effet, lorsqu’un calcul est fait avec des flottants, la machine :
- calcule la représentation des flottants en binaire ;
- réalise les calculs avec la représentation binaire ;
- détermine la représentation décimale du résultat binaire trouvé.
Or, contrairement aux nombres entiers, la représentation binaire d’un nombre flottant n’est pas toujours exacte.
En Python, 0.1 + 0.2 == 0.3 renvoie False alors qu’en mathématiques, on sait que la somme de 0,1 et de 0,2 vaut bien 0,3. Ce test est un exemple classique.
D’un point de vue pratique, cette contrainte d’utilisation des flottants peut mettre en difficulté le programmateur.
Si on considère la fonction f(x) = 2x et si on veut calculer f(0), puis f(0,1), puis f(0,2), …, jusqu’à f(0,9), on peut simplement avoir l’idée du code suivant où on ajoute à a = 0 successivement 0.1 : on n’atteindra jamais 1 car, avec Python, 0+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 ne vaut pas 1.
Python | Explication |
def f(x): return 2*x |
On définit la fonction f. |
a = 0 | On initialise la variable a à 0. |
while a != 1: | Tant que a est différente de 1, |
print(f(a)) | on calcule f(a), puis on affiche le résultat, |
a = a + 0.1 | puis on ajoute 0.1 à a. |
Mathématiquement, ce code est parfaitement correct. Toutefois, il ne s’arrête jamais.
Python Tutor met 999 étapes pour réaliser ce code car c’est son maximum d’itérations possibles. Pour pallier ce problème, on peut proposer le code suivant.
Python | Explication |
def f(x): return 2*x |
On définit la fonction f. |
a = 0 | On initialise la variable a à 0. |
while a < 1: | Tant que a est inférieur à 1, |
print(f(a)) | on calcule f(a), puis on affiche le résultat, |
a = a + 0.1 | puis on ajoute 0.1 à a. |
Le test a < 1 évite de demander une valeur exacte de a.
Vous avez obtenu75%de bonnes réponses !