Aller au contenu

La programmation défensive⚓︎

Les pré-conditions⚓︎

Une mauvaise saisie d'un utilisateur (qui entrerait par exemple un texte là où l'ordinateur lui demande un nombre) peut occasionner des comportements imprévus de votre programme, ce qui n'est pas désirable en pratique !

Dans le meilleur des mondes, l'utilisateur lirait la documentation de notre fonction et serait bienveillant :

🐍 Script Python
def puiss(x, n):
    """
    Calcule x^n
    :param float x: le nombre à élever à la puissance n
    :param int n: l'exposant de la puissance
    :return: la valeur de x^n
    :rtype: int
    :CU: il faut que x ne soit pas nul si n est négatif ou nul
    """
    return x ** n

ici nous avons précisé une condition d'utilisation (CU) que l'utilisateur devrait respecter (car \(0^{-3}\) n'existe pas par exemple).

Mais nous pouvons aussi éviter ce genre de problèmes à l'aide de pré-conditions ; testez la fonction suivante avec différentes valeurs de \(x\) et de \(n\) :

###

def puiss(x, n):bksl-nl """bksl-nl la docstring...bksl-nl """bksl-nl assert x!=0 or n>0, "x ne doit pas être nul quand n est négatif ou nul"bksl-nl p = 1bksl-nl for py-und in range(n):bksl-nl p = p py-str xbksl-nl return pbksl-nl

A

Z

Remarque

Nous ne pouvons pas calculer \(x^n\) quand \(x\) vaut 0 et \(n\) est négatif ou nul. En logique, le contraire de (x==0 ET n<=0) est (x!=0 OU n>0).

Et si nous ne voulons pas le programme s'arrête ?

Nous avons vu que nous pouvons utiliser de simples tests if ... else couplés à des print ; nous pouvons aussi simplement interrompre l'exécution de notre fonction avec un return, plus précisement un return None.

Les post-conditions⚓︎

Il est possible de tester si notre fonction va bien renvoyer ce qu'on attend d'elle, voici un exemple simpliste :

###

def puiss(x, n):bksl-nl """bksl-nl la docstring...bksl-nl """bksl-nl p = 1bksl-nl for py-und in range(n):bksl-nl p = p py-str xbksl-nl assert p == x py-strpy-str nbksl-nl return pbksl-nl

A

Z

Modifiez le code de façon à ce que la fonction ne fasse plus ce qui lui est demandé afin d'obtenir une AssertionError.

Exercice 4

La fonction suivante calcule le quotient et le reste dans une division euclidienne d'un nombre a par un nombre b (exemple : dans la division de 14 par 3, le quotient est 4 et le reste 2 car \(14=3\times4+2\)) :

###
def divisionpy-undeuclidienne(a, b):bksl-nl quotient = a // bbksl-nl reste = a - bpy-strquotientbksl-nl return (quotient, reste)bksl-nlbksl-nl# exemple de test :bksl-nlassert divisionpy-undeuclidienne(14, 3) == (4, 2)bksl-nl

Pour pouvoir utiliser cette fonction, il y a des contraintes sur a et b : ils doivent être des entiers et b ne doit pas être nul. Écrivez des pré-conditions et une post-condition pour cette fonction.

Exercice 5

Soit la fonction suivante renvoyant la valeur maximale présente dans un tableau d'entiers passé en paramètre :

###
def maxpy-undtableau(tab):bksl-nl maxpy-undvalue = tab[0]bksl-nl for nombre in tab:bksl-nl if nombre > maxpy-undvalue:bksl-nl maxpy-undvalue = nombrebksl-nl return maxpy-undvaluebksl-nlbksl-nl# un test :bksl-nlassert maxpy-undtableau([-2, 5, 10, 1, 12, 7, -3]) == 12bksl-nl

  1. Quelle est la précondition sur le tableau passé en paramètre ? (pensez au cas limite)
  2. Écrivez l'assertion correspondante.
  3. Donnez une deuxième version max_tableau_bis de cette fonction sans utiliser d'assertion mais en utilisant la valeur None comme valeur de retour.
    Source de cet exercice