{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Spécification et test d'une fonction\n", "\n", "Au delà des commentaires insérés dans le code pour expliciter une ligne ou un bloc de code, il est indispensable de **documenter les fonctions, les modules, les classes et les méthodes**. Ceci se fait à l’aide de **docstrings**. En classe de première on se limitera au cas des fonctions.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Exécuter tout d'abord cette cellule pour pouvoir disposer de la fonction d'affichage d'une matrice :\n", "def aff_matrice(mat):\n", " \"\"\" fonction qui affiche une matrice 'mat' sur l'écran du PC\n", " :param mat: la matrice à afficher\n", " :type mat: list\n", " :return: None \n", " \"\"\"\n", " for i in range(len(mat)):\n", " for j in range(len(mat[0])):\n", " print(mat[i][j] ,'\\t', end='')\n", " print('')\n", " print('')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1- Prototypage\n", "\n", "Une **docstring** est une chaîne de caractères placée *juste après la ligne de définition* de la fonction. Elle permet en Python de prototyper la fonction (penser à exécuter la cellule suivante) :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " \n", " :param mat1: une matrice\n", " :type mat1: list \n", " :param mat2: une matrice de mêmes dimensions que mat1\n", " :type mat2: list \n", " \n", " :return: une nouvelle matrice égale à mat1 + mat2\n", " :rtype: list\n", " \"\"\"\n", " \n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cette docstring est renvoyée par la fonction help() . Par exemple dans un interpréteur Python :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "help(add_matrices)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Elle fournira de précieuses informations au programmeur qui aura à utiliser cette fonction (ce programmeur sera parfois ... soi même après quelques semaines de non-utilisation de cette fonction!)\n", "\n", "Dans l’exemple ci-dessus, on remarque que la docstring occupe plus de lignes que le code de la fonction… Cela montre bien l’importance que revêt la documentation d’une fonction.\n", "\n", "La docstring est délimitée par une paire de triple guillemets et doit :\n", "\n", " • résumer le comportement de la fonction\n", " • documenter le(s) paramètre(s) en spécifiant le type pour chacun d’eux\n", " • documenter la (ou les) valeur(s) renvoyée(s) en spécifiant le type pour chacune d’elles \n", " \n", "Au niveau de la typographie, on aligne l’indentation du texte sur celle des triples guillemets.\n", "\n", "**Version réduite** :\n", "Il est possible d'alléger la *docstring* en remplaçant par une seule ligne, les deux lignes documentant un paramètre ou la valeur renvoyée (description et type).\n", "Ci-dessous la mise en application pour les deux fonctions précédentes (**compléter la docstring pour la deuxième fonction**) :\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Version allégées des fonctions précédentes :\n", "def aff_matrice(mat):\n", " \"\"\" fonction qui affiche une matrice 'mat' sur l'écran du PC\n", " :param mat: (list) la matrice à afficher\n", " :return: None \n", " \"\"\"\n", " for i in range(len(mat)):\n", " for j in range(len(mat[0])):\n", " print(mat[i][j] ,'\\t', end='')\n", " print('')\n", " print('')\n", "\n", "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " ??? ... écrire ici la portion de docstring manquante\n", " \n", " :return: (list) une nouvelle matrice égale à mat1 + mat2\n", " \"\"\"\n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]" ] }, { "source": [ "## 2. Pré-condition(s) et post-condition(s)\n", "\n", "### 2.1 Exemple d'appel de fonction correct :\n", "\n", "Pour que le code de la fonction s’exécute convenablement, il est nécessaire de lui fournir les **arguments** convenables. (*argument = valeur attribuée à un paramètre lors de l’appel de la fonction*)\n", "\n", "Dans le cas de la fonction add_matrices(mat1, mat2), mat1 ou mat2 sont les **paramètres formels** appelés aussi **paramètres** de la fonction. Observons le code suivant :" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1 = [[1, 2, 3], [4, 5, 6]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "\n", "m3 = add_matrices(m1,m2)\n", "print(m3)\n", "aff_matrice(m3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En ligne 5 on réalise l’appel de la fonction add_matrices( ). Les **paramètres formels** mat1 et mat2 sont alors remplacés par m1 et m2 que l’on appelle **paramètres effectifs** ou **arguments**.\n", "\n", "Ici tout se passe bien : le résultat obtenu est bien celui attendu. Pourquoi ? Car les **préconditions** à l’exécution du code de cette fonction sont intégralement réalisées. Quelles sont-elles ?\n", "\n", "**Préconditions :**\n", "\n", " • m1 et est une matrice (au sens mathématique) donc du point de vue Python une liste de listes. Toutes les \n", " sous-listes de m1 ont le même nombre d’éléments\n", " • même chose pour m2\n", " • et m1 et m2 sont de mêmes dimensions \n", " \n", "La **postcondition** (renvoi d’une matrice constituée de l’addition élément à élément des matrices m1 et m2 ) est alors réalisée.\n", "*La postcondition est une « promesse » de ce que l’on doit obtenir, si les préconditions requises sont remplies **et** si le code de la fonction est correct.*\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2 Exemples d'appels de fonction incorrects :\n", "\n", "On va envisager différents cas d'appels de fonctions dans lesquels une précondition n'est pas remplie.\n", "\n", "#### Cas où m1 et m2 n'ont pas les mêmes dimensions :\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# m1 a plus de colonnes que m2 :\n", "m1 = [[1, 2, 3, 4], [5, 6, 7, 8]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "m3 = add_matrices(m1,m2)\n", "\n", "aff_matrice(m3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Cas où les éléments constituants les sous-listes de m1 et/ou de m2 ne sont pas des nombres :** \n", "\n", "*Remarque* : pour cette démonstration on a utilisé des listes de listes dans lesquelles les éléments ne sont pas tous de même nature ... à éviter absolument !" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1 = [['un ', 'beau', 'pas '], [4, 5, 6]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "m3 = add_matrices(m1,m2)\n", "\n", "aff_matrice(m3)" ] }, { "source": [ "Expliquer pourquoi le code ci-dessous passe sans générer d'erreur :" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1 = [['un ', 'beau', 'pas '], [4, 5, 6]]\n", "aff_matrice(m1)\n", "m2 =[['peu', 'coup', 'du tout'], [16, 20, 24]]\n", "aff_matrice(m2)\n", "m3 = add_matrices(m1,m2)\n", "\n", "aff_matrice(m3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3- Tester et protéger le code\n", "\n", "On se propose de résoudre le problème des matrices qui ne seraient pas de même dimension lors de l'utilisation de la fonction add_matrices(mat1, mat2).\n", "\n", "Différentes façons s'offrent à nous pour y arriver.\n", "\n", "### 3.1- Avec l'instruction conditionnelle if :\n", "\n", "Compléter le code de la fonction suivante pour vérifier que mat1 et mat2 ont bien la même dimension. La fonction renvoie bien alors la somme des éléments des deux matrices ; sinon la fonction renvoie 'None'.\n", "\n", "Tester la fonction avec :\n", " * deux matrices de même dimension\n", " * deux matrices de dimensions différentes. Un nouveau problème devrait apparaître. D'où provient-il ; comment le résoudre ?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def add_matrices_V2(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " :param mat2: (list) une matrice de mêmes dimensions que mat1\n", " :return: (list) une nouvelle matrice égale à mat1 + mat2 ou None en cas d'erreur\n", " \"\"\"\n", " if len(mat1) == len(mat2) and len(mat1[0]) == len(mat2[0]):\n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]\n", " else:\n", " return None \n", " \n", "def aff_matrice_V2(mat):\n", " \"\"\" fonction qui affiche une matrice 'mat' sur l'écran du PC\n", " :param mat: (list) la matrice à afficher\n", " :return: None \n", " \"\"\"\n", " if mat != None:\n", " for i in range(len(mat)):\n", " for j in range(len(mat[0])):\n", " print(mat[i][j] ,'\\t', end='')\n", " print('')\n", " print('')\n", " else:\n", " print('une erreur est apparue')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "m1 = [[1, 2, 3], [4, 5, 6]]\n", "aff_matrice_V2(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice_V2(m2)\n", "\n", "m3 = add_matrices_V2(m1,m2)\n", "aff_matrice_V2(m3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# m1 a plus de colonnes que m2 :\n", "m1 = [[1, 2, 3, 4], [5, 6, 7, 8]]\n", "aff_matrice_V2(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice_V2(m2)\n", "m3 = add_matrices_V2(m1,m2)\n", "\n", "aff_matrice_V2(m3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.2 Avec l'instruction 'assert'\n", "\n", "Vocabulaire : une **assertion** est une proposition que l'on considère comme **vraie**.\n", "\n", "**assert** est une instruction qui fait partie des **mots clé (keywords)**, on dit aussi **'mots réservés'**, du langage Python. \n", "Beaucoup de ces mots clé nous sont déjà connus :\n", "\n", "![title](images/mots_cle.png)\n", "\n", "Syntaxe : assert *expression*\n", "\n", " * si l'évaluation de est Vraie alors le programme continue\n", " * si l'évaluation de renvoie None, False, 0 ou [] alors une exception ('AssertionError') est levée \n", " et le programme s'arrête. \n", "\n", "Dans le programme ci-dessous tester **tour à tour** les expressions suivantes :\n", " - 1 + 2 == 3\n", " - 1 + 2 != 3\n", " - not(True) == False\n", " - not(True) == True\n", " - not(False) != False\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('test')\n", "assert 1 + 2 == 3 # on place après assert l'expression à tester\n", "print('tout va bien !')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 3.2.1 ASSERTION SUR UNE PRECONDITION :\n", "\n", "Reprenons la fonction add_matrices(mat1, mat2) et utilisons assert pour vérifier que les deux matrices ont bien les mêmes dimensions (**assert est utilisé ici pour vérifier une précondition de la fonction add_matrice()**):" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# penser à exécuter cette cellule avant de passer à la suite \n", "\n", "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " :param mat2: (list) une matrice de mêmes dimensions que mat1\n", " :return: (list) une nouvelle matrice égale à mat1 + mat2\n", " \"\"\"\n", " assert len(mat1) == len(mat2) and len(mat1[0]) == len(mat2[0])\n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Utilisons maintenant cette fonction modiflée avec deux matrices de mêmes dimensions puis deux matrices de dimensions différentes :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ce code doit réussir :\n", "m1 = [[1, 2, 3], [4, 5, 6]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "\n", "m3 = add_matrices(m1,m2)\n", "aff_matrice(m3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# ce code doit échouer :\n", "# m1 a plus de colonnes que m2 :\n", "m1 = [[1, 2, 3, 4], [5, 6, 7, 8]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "m3 = add_matrices(m1,m2)\n", "\n", "aff_matrice(m3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 3.2.2- ASSERTION SUR UNE POSTCONDITION :\n", "\n", "Il s’agit ici de **vérifier que la fonction réalise bien ce pour quoi elle a été conçue**. On suppose bien évidemment que les *préconditions soient parfaitement remplies avant de passer à ce type de tests*.\n", "\n", "L'assertion est cette fois placée **en dehors** de la fonction.\n", "\n", "Dans le programme suivant la fonction est correcte et le test doit passer. Le vérifier.\n", "\n", "On va maintenant regarder ce qui se passe s'il y a une erreur dans le code (ce ne sera pas une erreur de syntaxe car il faut que le code puisse être exécuté jusqu'à l'assertion placé en fin de code). \n", "On propose de remplacer dans la ligne **return ...** l'addition entre deux éléments des matrices :\n", "\n", "mat1\\[i]\\[j] + mat2\\[i]\\[j] \n", "\n", "par une multiplication :\n", "\n", "mat1\\[i]\\[j] * mat2\\[i]\\[j] \n", "\n", "La fonction ne va donc pas renvoyer le résultat que l'on attend ce qui fait que l'instruction finale :\n", "\n", "assert add_matrices(m1,m2) == \\[\\[5, 10, 15], \\[20, 25, 30]]\n", "\n", "va générer une **AssertionError**" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " :param mat2: (list) une matrice de mêmes dimensions que mat1\n", " :return: (list) une nouvelle matrice égale à mat1 + mat2\n", " \"\"\"\n", " assert len(mat1) == len(mat2) and len(mat1[0]) == len(mat2[0])\n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]\n", "\n", "# test de la fonction :\n", "m1 = [[1, 2, 3], [4, 5, 6]]\n", "aff_matrice(m1)\n", "m2 =[[4, 8, 12], [16, 20, 24]]\n", "aff_matrice(m2)\n", "\n", "assert add_matrices(m1,m2) == [[5, 10, 15], [20, 25, 30]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3.3 Application :\n", "\n", "Reprendre la fonction d'affichage de matrice pour la carte Micro:Bit et inclure un test permettant de vérifier la précondition : 'la matrice passée en argument est bien de type 5x5' " ] }, { "source": [ "## 4- doctest : un module pour mieux documenter et en même temps tester le code : \n", "\n", "### 4.1- Présentation :\n", "\n", "Ce module fait partie de la distribution de Python et n'a donc pas besoin d'être installé. Il faudra par contre l'importer si on souhaite l'utiliser.\n", "\n", "On utilisera dans ce module la fonction **testmod()** qui va : \n", " - analyser la docstring\n", " - repérer s'il y a dedans du code exécutable et le résultat prévu\n", " - exécuter ce code\n", " - comparer le résultat obtenu à celui prévu et renvoyer une information en conséquence\n", "\n", "Cette fonction testmod() a de nombreux paramètres tous prédéfinis. L'un deux, **verbose** ( = *verbeux*, autrement dit *bavard*) permet d'afficher le compte rendu détaillé de l'exécution de la fonction. On le réglera à la valeur **True** :\n", "\n", "**doctest.testmod(verbose=True)**\n", "\n", "Le code à tester devra être écrit **comme dans un interpréteur** :\n", " - il débute par 3 chevrons : >>> **suivis par un espace**\n", " - **ATTENTION** : ne pas mettre d'espace(s) au bout de la ligne du résultat attendu (la fonction teste les chaînes des caractères attendues et obtenues et un espace de trop les rendrait différentes!!!)\n", " - le résultat attendu est placé au début de la ligne suivante \n", "\n", "### 4.2- Exemples : \n", "\n", "L'utilisation de la fonction d'addition entre deux matrices pourrait donner dans un interpréteur le résultat suivant :\n", "\n", "![image : specification.png](images/specification.png)\n", "\n", "Observer la mise en place de cet exemple dans la docstring de la fonction ci-dessous et l'utilisation de la fonction testmod(). La cellule est prête : il y a juste à l'exécuter :" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "import doctest\n", "\n", "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " :param mat1: (list) une matrice \n", " :return: (list) une nouvelle matrice égale à mat1 + mat2\n", " \n", " Exemples :\n", " >>> m1 = [[1, 2, 3], [4, 5, 6]]\n", " >>> m2 =[[4, 8, 12], [16, 20, 24]]\n", " >>> add_matrices(m1, m2) \n", " [[5, 10, 15], [20, 25, 30]]\n", " >>> \n", " \"\"\"\n", " return [[mat1[i][j] + mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]\n", "\n", "\n", "doctest.testmod(verbose = True)" ] }, { "source": [ "On reprend ci-dessous la cellule précédente mais au niveau de l'instruction *return*, on a remplacé l'addition entre les matrices par une multiplication : quand la fonction va être exécutée, le résultat obtenu sera différent de celui attendu... Lancer l'exécution de la cellule et observer le résutat :" ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import doctest\n", "\n", "def add_matrices(mat1, mat2):\n", " \"\"\"\n", " réalise la somme de deux matrices 'mat1' et 'mat2'\n", " :param mat1: (list) une matrice\n", " :param mat1: (list) une matrice \n", " :return: (list) une nouvelle matrice égale à mat1 + mat2\n", " \n", " Exemples :\n", " >>> m1 = [[1, 2, 3], [4, 5, 6]]\n", " >>> m2 =[[4, 8, 12], [16, 20, 24]]\n", " >>> add_matrices(m1, m2) \n", " [[5, 10, 15], [20, 25, 30]]\n", " >>> \n", " \"\"\"\n", " # on a fait une erreur en codant la fonction :\n", " return [[mat1[i][j] * mat2[i][j] for j in range(len(mat1[0])) ] for i in range(len(mat2))]\n", "\n", "\n", "doctest.testmod(verbose = True)" ] }, { "source": [ "### 4.3- Bonne pratique\n", "\n", "Une bonne pratique en programmation consiste à :\n", "\n", " - commencer par écrire dans la docstring la spécification de la fonction :\n", " - rédiger une ligne de présentation de la fonction\n", " - préciser le(s) paramètre(s) et leur type\n", " - préciser si elle existe la valeur renvoyée et son type\n", " - puis ajouter :\n", " - d'éventuelles conditions d'utilisation de la fonction\n", " - les éventuels *effets de bords* (notion qui sera développée progressivement dans le cours)\n", " - un ou plusieurs exemples, de code avec le(s) résultat(s) attendu(s)\n", " - et **seulement après, commencer à écrire le code de la fonction !**\n", "\n", "*Remarque* : Lorsqu'il y a plusieurs fonctions dans le code, toutes celles dont la docstring présente un exemple de code passeront au crible de doctest.testmod(). \n", "\n", "A titre d'exemple, dans la cellule ci-dessous, on demande d'écrire deux fonctions :\n", " - l'une qui calcule la vitesse moyenne (en km/h) d'un véhicule, connaissant la distance parcourue (en km) et la durée du parcours (en heures)\n", " - l'autre qui calcule la distance (en km) parcourue par un véhicule roulant à une vitesse connue (en km/h) pendant une durée déterminée (en heures)\n", "\n", "On rédigera pour chacune de ces fonctions une docstring complète avec deux exemples de résultats attendus. Puis on écrira le code de chaque fonction et on réalisera le test avec doctest.testmod(). Le calcul de la vitesse nécessite de prendre une précaution pour éviter une erreur. Laquelle ?\n", "\n", "Vérifier que les deux docstrings sont bien scrutées par testmod()." ], "cell_type": "markdown", "metadata": {} }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Trying:\n distance_parcourue(120, 3)\nExpecting:\n 360\nok\nTrying:\n distance_parcourue(60, 2.5)\nExpecting:\n 150.0\nok\nTrying:\n vitesse(100, 2)\nExpecting:\n 50.0\nok\nTrying:\n vitesse(0, 2)\nExpecting:\n 0.0\nok\n1 items had no tests:\n __main__\n2 items passed all tests:\n 2 tests in __main__.distance_parcourue\n 2 tests in __main__.vitesse\n4 tests in 3 items.\n4 passed and 0 failed.\nTest passed.\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "TestResults(failed=0, attempted=4)" ] }, "metadata": {}, "execution_count": 3 } ], "source": [ "def vitesse(distance, duree):\n", " \"\"\" fonction qui calcule en km/h la vitesse moyenne d'un mobile\n", " :param distance: (float) la distance parcourue (en km)\n", " :param duree: (float) la durée du parcours (en h)\n", " :return: (float) la vitesse calculée\n", " Exemple\n", " >>> vitesse(100, 2)\n", " 50.0\n", " >>> vitesse(0, 2)\n", " 0.0\n", " \"\"\"\n", " assert duree != 0\n", " return distance / duree\n", "\n", "def distance_parcourue(vitesse, duree):\n", " \"\"\" fonction qui calcule la distance parcourue par un véhicule\n", " :param vitesse: (float) la vitesse en km/h\n", " :param duree: (float) la durée en heures\n", " :return: (float) la distance en km\n", " Exemples:\n", " >>> distance_parcourue(120, 3)\n", " 360\n", " >>> distance_parcourue(60, 2.5)\n", " 150.0\n", " \"\"\"\n", " return vitesse*duree\n", "\n", "import doctest\n", "doctest.testmod(verbose=True)" ] }, { "source": [ "### 4.4- Tester les fonctions d'un module de fonctions\n", "\n", "Un module de fonctions ne contient que des définitions de fonctions, donc pas de code exécutable car il n'est sensé être utilisé qu'en *importation*.\n", "A priori, on ne doit donc pas y écrire les instructions :\n", "\n", "import doctest\n", "\n", "doctest.testmod(verbose=True)\n", "\n", "On peut néanmoins insérer ces instructions pour qu'elles soient **exécutées sous condition.**\n", "\n", "A la fin du module de fonctions (donc à la suite de **toutes** les définitions de fonctions, on insère le code suivant :\n", "\n", " if __name__ == '__main__':\n", " \n", " import doctest\n", " \n", " doctest.testmod(verbose=True)\n", "\n", "Explication : \\__name\\__ est une variable interne qui prend :\n", "\n", " - le nom du module lorsqu'il est importé\n", " - le nom '\\__main\\__' lorsque le module est lancé comme un script quelconque\n", "\n", "Si on lance l'exécution de ce module de fonction, \\__name\\__ prend alors la valeur '\\__main\\__' .\n", "\n", "Le test if \\__name\\__ == '\\__main\\__' renvoie donc True et le code qui suit est exécuté, ce qui lance la méthode testmod() sur l'intégralité du fichier.\n", "\n" ], "cell_type": "markdown", "metadata": {} } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3-final" } }, "nbformat": 4, "nbformat_minor": 2 }