Le mot anglais bug appartient au jargon des ingénieurs de matériel et représentant les problèmes qui y survenaient. L'utilisation du terme pour décrire les défauts de systèmes mécaniques date d'au moins avant les années 1870. Thomas Edison, entre autres, utilisait le mot dans ses notes..
Dans la pratique de la programmation, il faut savoir répondre aux causes typiques de bugs , notamment :
A faire dans le cahier.
Donner un exemple court de code Python illustrant chacun des points ci-dessus.
Il existe quelques bonnes pratiques à avoir lorsque l'on écrit un programme Python :
ma_variable
,
liste_des_diviseurs
etc.PI=3.14159
(oui, ce n'est pas sa valeur réelle..)import math
au lieu de from math import *
def uniquement_positif(liste):
for element in liste : #Pour tous les éléments de la liste
if element < 0 : #On trouve un élément négatif.
return False
return True #On renvoie Vrai si on n'a pas trouvé de nombre négatif.
Ecrire une fonction divisible_par_7_et_par_5
qui prend en paramètre un nombre entier x
supérieur ou égal à 1 et qui retourne un integer.
Elle doit renvoyer :
0
s'il n'est divisible ni par 5 ni par 7.2
s'il est divisible par 5 et par 7.1
s'il est divisible par 5 ou 7, mais pas par les deux.Ce code doit être commenté et en ayant fait attention d'avoir "de bonnes pratiques".
Documenter une fonction a aussi son importance.
On écrit la documentation d'une fonction juste après la ligne def
en commençant par ''' et finissant
par '''.
On peut accéder à une documentation à l'aide de la fonction help.
Exemple:
def uniquement_negatif(liste):
'''
Fonction prenant en paramètre une liste de nombres et renvoyant un booléen.
Elle renvoie True si tous les nombres sont strictement négatifs et False sinon.
'''
for element in liste :
if element >= 0 :
return False
return True
Ecrire une fonction diviseur
qui prend en paramètre un nombre entier x
supérieur ou
égal à 1 et qui retourne la
liste de tous ses diviseurs.
Ce programme retournera soit une liste contenant les diviseurs , soit False si le paramètre n'a pas le bon format. Ce code doit être documenté, commenté et en ayant fait attention d'avoir "de bonnes pratiques".
Dans la pratique de la programmation, nous pouvons faire des assertions.
Une assertion est suivi d'un test. Si le test retourne Vrai, alors rien ne se passe. Par contre, si le test retourne Faux, alors le programme est immédiatement arrété.
On appelle cela de la programmation défensive. Le but est de s'assurer que le code n'est pas utilisé de manière maladroite ou frauduleusement.
En Python, il s'agit de la commande assert
.
Les assertions peuvent aussi être utilisées à côté d'une fonction pour prouver sa bonne marche.
Le PGCD de deux nombres entiers supérieurs ou égaux à 1 est le plus grand de leur diviseur en commun.
Ecrire une fonction pgcd
qui prend en paramètres deux nombres entiers supérieurs ou égaux à 1 :
a
et b
.
Ce programme retournera un integer correspondant au PGCD de ces deux nombres, ou sera arrêté si les paramètres n'ont pas le bon format à l'aide d'une ou plusieurs assertions.
Ce programme sera documenté et commenté.
Un nombre entier positif non nul est premier s'il comporte exactement deux diviseurs.
Ecrire une fonction decompo_facteurs_premiers
qui prend en paramètre un integer n
correspondant à un entier supérieur
ou égal à 1 et qui renvoie la liste des nombres correspondant à sa décomposition en facteur premiers.
Ce programme sera documenté, commenté et comportera des assertions.
Exemple de décomposition en facteurs premiers :
$$ 30=2 \times 15 = 2 \times 3 \times 5 $$Ecrire une fonction qui prend en paramètre un tableau d'entiers non vide et qui renvoie la moyenne de ces entiers. La fonction est spécifiée ci-après et doit passer les assertions fournies.
def moyenne (tab):
'''
moyenne(list) -> float
Entrée : un tableau non vide d'entiers
Sortie : nombre de type float
Correspondant à la moyenne des valeurs présentes dans le
tableau
'''
...
assert moyenne([1]) == 1
assert moyenne([1, 2, 3, 4, 5, 6, 7]) == 4
assert moyenne([1, 2]) == 1.5
En Python, il est possible de spécifier le type des paramètres d'une fonction. Cela permet de clarifier l'intention du programmeur et d'améliorer la lisibilité du code.
Le typage n'est pas obligatoire en Python, car il s'agit d'un langage dynamiquement typé. Cependant, depuis la version 3.5, Python permet d'annoter les paramètres des fonctions avec des types.
Par exemple, une fonction qui prend un entier et retourne un entier peut être définie comme suit:
def carre(nombre: int) -> int:
return nombre * nombre
Dans cet exemple, nombre: int
indique que le paramètre nombre
doit être de type
int
(un entier), et -> int
spécifie que la fonction retourne un entier.
Bien que ces annotations de type n'imposent pas de contraintes strictes au moment de l'exécution, elles servent à documenter le code et peuvent être utilisées par des outils d'analyse statique pour détecter des erreurs potentielles.
Le typage des paramètres de fonction est particulièrement utile dans les grands projets où plusieurs développeurs collaborent. Il aide à prévenir les erreurs en communiquant clairement les attentes concernant les types de données.
Programmer la fonction recherche
qui prend en paramètres un nombre entier elt
et un
tableau tab
de nombres entiers, et qui renvoie l’indice de la première occurrence de
elt
dans tab
si elt
est dans tab
et -1
sinon.
Ne pas oublier d’ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour vérifier les pré-conditions.
Exemples :
>>> recherche(1, [2, 3, 4])
-1
>>> recherche(1, [10, 12, 1, 56])
2
>>> recherche(50, [1, 50, 1])
1
>>> recherche(15, [8, 9, 10, 15])
3
>>> recherche(50, [])
-1
>>> recherche(4, [2, 4, 4, 3, 4])
1
Écrire une fonction max_et_indice
qui prend en paramètre une liste non vide tab
de
nombres entiers et qui renvoie la valeur du plus grand élément de cette liste ainsi que
l’indice de sa première apparition dans cette liste.
L’utilisation de la fonction native max
n’est pas autorisée.
Ne pas oublier d’ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour vérifier les pré-conditions.
Exemples :
>>> max_et_indice([1, 5, 6, 9, 1, 2, 3, 7, 9, 8])
(9, 3)
>>> max_et_indice([-2])
(-2, 0)
>>> max_et_indice([-1, -1, 3, 3, 3])
(3, 2)
>>> max_et_indice([1, 1, 1, 1])
(1, 0)
Écrire une fonction min_et_max
qui prend en paramètre un tableau de nombres tab
non
vide, et qui renvoie la plus petite et la plus grande valeur du tableau sous la forme d’un
dictionnaire à deux clés 'min'
et 'max'
.
Les tableaux seront représentés sous forme de liste Python.
L’utilisation des fonctions natives min
, max
et sorted
, ainsi que la
méthode sort
n’est pas
autorisée.
Ne pas oublier d’ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour vérifier les pré-conditions.
Exemples :
>>> min_et_max([0, 1, 4, 2, -2, 9, 3, 1, 7, 1])
{'min': -2, 'max': 9}
>>> min_et_max([0, 1, 2, 3])
{'min': 0, 'max': 3}
>>> min_et_max([3])
{'min': 3, 'max': 3}
>>> min_et_max([1, 3, 2, 1, 3])
{'min': 1, 'max': 3}
>>> min_et_max([-1, -1, -1, -1, -1])
{'min': -1, 'max': -1}
Écrire une fonction couples_consecutifs
qui prend en paramètre une liste de
nombres entiers tab
non vide, et qui renvoie la liste (éventuellement vide) des couples
d'entiers consécutifs successifs qu'il peut y avoir dans tab
.
Ne pas oublier d’ajouter au corps de la fonction une documentation et une ou plusieurs assertions pour vérifier les pré-conditions.
Exemples :
>>> couples_consecutifs([1, 4, 3, 5])
[]
>>> couples_consecutifs([1, 4, 5, 3])
[(4, 5)]
>>> couples_consecutifs([1, 1, 2, 4])
[(1, 2)]
>>> couples_consecutifs([7, 1, 2, 5, 3, 4])
[(1, 2), (3, 4)]
>>> couples_consecutifs ([5, 1, 2, 3, 8, -5, -4, 7])
[(1, 2), (2, 3), (-5, -4)]