Chapitre 1 : Gestion des bugs et bonnes pratiques.

🕐 Historique:

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..

Source : wikipedia

1. Gestion des causes typiques de bugs:

Dans la pratique de la programmation, il faut savoir répondre aux causes typiques de bugs , notamment :

  1. problèmes liés au typage
  2. instruction conditionnelle non exhaustive
  3. débordements dans les tableaux
  4. choix des inégalités
  5. comparaisons et calculs des nombres flottants
  6. mauvais nommage des variables

2. Exercice

A faire dans le cahier.

Donner un exemple court de code Python illustrant chacun des points ci-dessus.

3. Quelques bonnes pratiques:

Il existe quelques bonnes pratiques à avoir lorsque l'on écrit un programme Python :

4. Exemple:

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.

5. Exercice :

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 :

Ce code doit être commenté et en ayant fait attention d'avoir "de bonnes pratiques".

6. La documentation des fonctions (docstring):

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    

7. Exercice :

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".

8. L'assertion en informatique:

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.

9. Exercice :

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é.

10. Exercice :

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 $$

11. Exercice : (sujet 28 - 2023)

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

12. Le typage des paramètres de fonction en Python:

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.

13. Exercice : (sujet 14 - 2023)

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

14. Exercice : (sujet 18 - 2023)

É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)

15. Exercice : (sujet 32 - 2023)

É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}

16. Exercice : (sujet 36 - 2023)

É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)]