vous avez bien sûr le droit de définir des fonctions intermédiaires qui ne sont pas demandées, lorsque vous jugez cela pertinent. Lisez l’énoncé en entier avant de commencer pour repérer les éventuelles opérations qui se répètent souvent.
dans cet exercice, vous avez souvent besoin de convertir un mot en liste de lettres. Pour cela, il faut utiliser list(…) comme dans l’exemple suivant: list(‘oui’) vaut [‘o’, ‘u’, ‘i’].
on suppose que tous les mots considérés dans cet exercice ne contiennent que des lettres, sans accents et en minuscule (pas de caractères spéciaux, tirets, espaces, etc…)
1) Ecrire une fonction commence_par prenant en
argument une lettre et un mot et qui renvoie True
si le mot commence par la lettre donnée en argument, False
sinon.
Test:
commence_par('h', 'hello') vaut True
mais commence_par('e', 'roue') vaut False.
2) Ecrire une fonction contient_voyelle qui prend
en argument un mot et qui renvoie True
si le mot contient une voyelle, False
sinon.
3) Ecrire une fonction derniere_consonne qui
prend en argument un mot et qui renvoie deux valeurs de retour:
l’indice de sa dernière consonne ainsi que la dernière consonne
(comme pour les listes, on considérera que l’indice de la première
lettre est zéro). On ne traitera pas le cas problématique où le
mot ne contient pas de consonne.
Test::
derniere_consonne('arrivee') renvoie 4, ‘v’
4) Ecrire une fonction double_consonne qui prend
en argument un mot et qui a deux valeurs de retour: un booléen
valant True si le
mot contient une double consonne (deux fois la même consonne à la
suite), et dans ce cas la deuxième valeur de retour est la consonne
qui est doublée ; s’il n’y a pas de consonne doublée, la
fonction doit renvoyer False
et None. Pour
information: pour simplifier l’exercice, on ne testera pas votre
fonction sur un mot contenant plusieurs double consonnes (par
exemple, ‘successeur’).
Test:
double_consonne('arrivee') vaut True, ‘r’.
double_consonne('bonbon') vaut False, None
double_consonne('reussite') vaut True, ‘s’
5) Ecrire une fonction envers qui prend en
argument une liste li
(attention, pas un mot, contrairement aux autres fonctions de cet
exercice) et qui renvoie une liste obtenue à partir de li
en inversant l’ordre des éléments.
6) Ecrire une fonction palindrome qui prend en
argument un mot et qui renvoie un booléen indiquant si le mot est un
palindrome. Un palindrome est un mot qui reste identique lorsqu’il
est lu de droite à gauche au lieu de l’ordre habituel de gauche à
droite.
Test:
palindrome('ici') vaut True
mais palindrome('aller') vaut False.
7) Ecrire une fonction mot_autorise prenant en
argument un mot et une liste de mots interdits, et qui renvoie True
si le mot est autorisé, et False
si le mot est interdit.
Comme les listes, les dictionnaires permettent de « stocker » des
données. Chaque élément d’un dictionnaire est composé de 2 parties, on
parle de pairs « clé/valeur ». Voici un exemple de dictionnaire :
mon_dico = {"nom": "Durand", "prenom": "Christophe", "date de naissance": "29/02/1981"}
Comme vous pouvez le constater, nous utilisons des accolades {}
pour définir le début et la fin du dictionnaire (alors que nous
utilisons des crochets [] pour les listes et les parenthèses pour les
tuples).
Dans le dictionnaire ci-dessus, « nom », « prenom » et « date de
naissance » sont des clés et « Durand », « Christophe » et « 29/02/1981 » sont
des valeurs.
La clé « nom » est associée à la valeur « Durand », la clé « prenom » est
associée à la valeur « Christophe » et la clé « date de naissance » est
associée à la valeur « 29/02/1981 ».
Les clés sont des chaînes de caractères ou des nombres. Les valeurs
peuvent être des chaînes de caractères, des nombres, des booléens…
Pour créer un dictionnaire, il est aussi possible de procéder comme suit :
La variable « mon_dico » référence un dictionnaire. Il est
possible d’afficher le contenu du dictionnaire référencé par la variable
« mon_dico » en saisissant « mon_dico » dans la console. Faites le test
après avoir exécuté le programme ci-dessous.
mon_dico = {"nom": "Durand", "prenom": "Christophe", "date de naissance": "29/02/1981"}
Il est possible d’afficher la valeur associée à une clé :
À faire vous-même 2
Soit le programme suivant :
mon_dico = {"nom": "Durand", "prenom": "Christophe", "date de naissance": "29/02/1981"}
print(f'Bonjour je suis {mon_dico["prenom"]} {mon_dico["nom"]}, je suis né le {mon_dico["date de naissance"]}')
Quel est le résultat attendu après l’exécution de ce programme ? Vérifiez votre réponse.
Il est facile d’ajouter un élément à un dictionnaire (les dictionnaires sont mutables)
À faire vous-même 3
Soit le programme suivant :
mon_dico = {"nom": "Durand", "prenom": "Christophe", "date de naissance": "29/02/1981"}
print(f'Bonjour je suis {mon_dico["prenom"]} {mon_dico["nom"]}, je suis né le {mon_dico["date de naissance"]}')
mon_dico['lieu naissance'] = "Bonneville"
print (f'à {mon_dico["lieu naissance"]}')
Quel est le résultat attendu après l’exécution de ce programme ? Vérifiez votre réponse.
L’instruction « del » permet du supprimer une paire « clé/valeur »
À faire vous-même 4
Quel est le contenu du dictionnaire référencé par la variable
« mes_fruits » après l’exécution du programme ci-dessous ? Vérifiez votre
réponse à l’aide de la console.
mes_fruits = {"poire": 3, "pomme": 4, "orange": 2}
del mes_fruits["pomme"]
Quel est le contenu du dictionnaire référencé par la variable
« mes_fruits » après l’exécution du programme ci-dessus ? Vérifiez votre
réponse à l’aide de la console.
Il est possible de parcourir un dictionnaire à l’aide d’une boucle for. Ce parcours peut se faire selon les clés ou les valeurs.
Commençons par parcourir les clés à l’aide de la méthode « keys »
À faire vous-même 6
Tester le programme suivant :
mes_fruits = {"poire": 3, "pomme": 4, "orange": 2}
print("liste des fruits :")
for fruit in mes_fruits.keys():
print(fruit)
La méthode values() permet de parcourir le dictionnaire selon les valeurs
À faire vous-même 7
Tester le programme suivant :
mes_fruits = {"poire": 3, "pomme": 4, "orange": 2}
for qte in mes_fruits.values():
print(qte)
Enfin, il est possible de parcourir un dictionnaire à la fois sur les clés et les valeurs en utilisant la méthode items().
À faire vous-même 8
Tester le programme suivant :
mes_fruits = {"poire": 3, "pomme": 4, "orange": 2}
print ("Stock de fruits :")
for fruit, qte in mes_fruits.items():
print (f"{fruit} : {qte}")
Vous avez sans doute remarqué l’utilisation de deux variables (« fruit » et « qte ») au niveau du « for…in »
Voici ci dessous des slides sur les dictionnaires réalisés par:–Amir Charif–Lydie Du Bousquet–Aurélie Lagoutte–Julie Peyre–Florence Thiard
Il est possible de « stocker » plusieurs grandeurs dans une même
structure, ce type de structure est appelé une séquence. De façon plus
précise, nous définirons une séquence comme un ensemble fini et ordonné
d’éléments indicés de 0 à n-1 (si cette séquence comporte n éléments).
Rassurez-vous,
nous reviendrons ci-dessous sur cette définition. Nous allons étudier
plus particulièrement 2 types de séquences : les tuples et les tableaux
(il en existe d’autres que nous n’évoquerons pas ici).
Les tuples en Python
Comme déjà dit ci-dessus, un tuple est une séquence. Voici un exemple très simple :
mon_tuple = (5, 8, 6, 9)
Dans le code ci-dessus, la variable « mon_tuple » référence un tuple,
ce tuple est constitué des entiers 5, 8, 6 et 9. Comme indiqué dans la
définition, chaque élément du tuple est indicé (il possède un indice):
le premier élément du tuple (l’entier 5) possède l’indice 0
le deuxième élément du tuple (l’entier 8) possède l’indice 1
le troisième élément du tuple (l’entier 6) possède l’indice 2
le quatrième élément du tuple (l’entier 9) possède l’indice 3
Comment accéder à l’élément d’indice i dans un tuple ?
Simplement en utilisant la « notation entre crochets » :
À faire vous-même 1
Testez le code suivant :
mon_tuple = (5, 8, 6, 9)
a = mon_tuple[2]
Quelle est la valeur référencée par la variable a (utilisez la console pour répondre à cette question)?
La variable mon_tuple référence le tuple (5, 8, 6, 9), la variable a
référence l’entier 6 car cet entier 6 est bien le troisième élément du
tuple, il possède donc l’indice 2
ATTENTION : dans les séquences les indices commencent toujours à 0
(le premier élément de la séquence a pour indice 0), oublier cette
particularité est une source d’erreur « classique ».
À faire vous-même 2
Complétez le code ci-dessous (en remplaçant les ..) afin qu’après
l’exécution de ce programme la variable a référence l’entier 8.
mon_tuple = (5, 8, 6, 9)
a = mon_tuple[..]
Un tuple ne contient pas forcément des nombres entiers, il peut aussi
contenir des nombres décimaux, des chaînes de caractères, des
booléens…
À faire vous-même 3
Quel est le résultat attendu après l’exécution de ce programme ?
Grâce au tuple, une fonction peut renvoyer plusieurs valeurs :
À faire vous-même 4
Analysez puis testez le code suivant :
def add(a, b):
c = a + b
return (a, b, c)
mon_tuple = add(5, 8)
print(f"{mon_tuple[0]} + {mon_tuple[1]} = {mon_tuple[2]}")
Il faut bien comprendre dans l’exemple ci-dessus que la variable
mon_tuple référence un tuple (puisque la fonction « add » renvoie un
tuple), d’où la « notation entre crochets » utilisée avec mon_tuple
(mon_tuple[1]…)
La console permet d’afficher les éléments présents dans un tuple simplement en :
À faire vous-même 5
Après avoir exécuté le programme ci-dessous, saisissez mon_tuple dans la console.
mon_tuple = (5, 8, 6, 9)
Il est possible d’assigner à des variables les valeurs contenues dans un tuple :
À faire vous-même 6
a, b, c, d = (5, 8, 6, 9)
Quelle est la valeur référencée par la variable a ? La variable b ?
La variable c ? La variable d ? Vérifiez votre réponse à l’aide de la
console Python.
Les tableaux ou liste en Python
ATTENTION : Dans la suite nous allons employer le terme « tableau ».
Pour parler de ces « tableaux » les concepteurs de Python ont choisi
d’utiliser le terme de « list » (« liste » en français). Pour éviter toute
confusion,
notamment par rapport à des notions qui seront abordées en terminale,
le choix a été fait d’employer « tableau » à la place de « liste » (dans la
documentation vous rencontrerez le terme « list », cela ne devra pas vous
pertuber)
Il n’est pas possible de modifier un tuple après sa création (on parle
d’objet « immutable »), si vous essayez de modifier un tuple existant,
l’interpréteur Python vous renverra une erreur.
Les tableaux sont,comme les tuples, des séquences, mais à la
différence des tuples, ils sont modifiables (on parle d’objets
« mutables »).
Pour créer un tableau, il existe différentes méthodes : une de ces méthodes ressemble beaucoup à la création d’un tuple :
mon_tab = [5, 8, 6, 9]
Notez la présence des crochets à la place des parenthèses.
Un tableau est une séquence, il est donc possible de « récupérer » un
élément d’un tableau à l’aide de son indice (de la même manière que pour
un tuple)
À faire vous-même 7
Quelle est la valeur référencée par la variable ma_variable après
l’exécution du programme ci-dessous ? (utilisez la console pour vérifier
votre réponse)
mon_tab = [5, 8, 6, 9]
ma_variable = mon_tab[2]
N.B. Il est possible de saisir directement mon_tab[2] dans la console
sans passer par l’intermédiaire de la variable ma_variable
Il est possible de modifier un tableau à l’aide de la « notation entre crochets » :
À faire vous-même 8
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
mon_tab = [5, 8, 6, 9]
mon_tab[2] = 15
Comme vous pouvez le constater avec l’exemple ci-dessus, l’élément
d’indice 2 (le nombre entier 6) a bien été remplacé par le nombre entier
15
Il est aussi possible d’ajouter un élément en fin de tableau à l’aide de la méthode « append » :
À faire vous-même 9
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
mon_tab = [5, 8, 6, 9]
mon_tab.append(15)
L’instruction « del » permet de supprimer un élément d’un tableau en utilisant son index :
À faire vous-même 10
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
mon_tab = [5, 8, 6, 9]
del mon_tab[1]
La fonction « len » permet de connaitre le nombre d’éléments présents dans une séquence (tableau et tuple)
À faire vous-même 11
Quelle est la valeur référencée par la variable nb_ele après l’exécution du programme ci-dessous ? (utilisez la console pour vérifier votre réponse)
mon_tab = [5, 8, 6, 9]
nb_ele = len(mon_tab)
Une petite parenthèse : on pourrait s’interroger sur l’intérêt
d’utiliser un tuple puisque le tableau permet plus de choses ! La
réponse est simple : les opérations
sur les tuples sont plus « rapides ». Quand vous savez que votre
tableau ne sera pas modifié, il est préférable d’utiliser un tuple à la
place d’un tableau.
la boucle « for » : parcourir les éléments d’un tableau
La boucle for… in permet de parcourir chacun des éléments d’une séquence (tableau ou tuple) :
À faire vous-même 12
Analysez puis testez le code suivant :
mon_tab = [5, 8, 6, 9]
for element in mon_tab:
print(element)
Quelques explications : comme son nom l’indique, la boucle « for » est
une boucle ! Nous « sortirons » de la boucle une fois que tous les
éléments du tableau mon_tab auront
été parcourus. element est une variable qui va :
au premier tour de boucle, référencer le premier élément du tableau (l’entier 5)
au deuxième tour de boucle, référencer le deuxième élément du tableau (l’entier 8)
au troisième tour de boucle, référencer le troisième élément du tableau (l’entier 6)
au quatrième tour de boucle, référencer le quatrième élément de le tableau (l’entier 9)
Une chose importante à bien comprendre : le choix du nom de la
variable qui va référencer les éléments du tableau les uns après les
autres (element) est totalement arbitraire,
il est possible de choisir un autre nom sans aucun problème, le code
suivant aurait donné exactement le même résultat :
mon_tab = [5, 8, 6, 9]
for toto in mon_tab:
print (toto)
Dans la boucle for… in il est possible d’utiliser la fonction prédéfinie range à la place d’un tableau d’entiers :
À faire vous-même 13
Analysez puis testez le code suivant :
for element in range(0, 5):
print (element)
Comme vous pouvez le constater, « range(0,5) » est, au niveau de la
boucle « for..in », équivalent au tableau [0,1,2,3,4], le code ci-dessous
donnerait le même résultat que le programme vu dans le « À faire
vous-même 12 » :
mon_tab = [0, 1, 2, 3, 4]
for element in mon_tab:
print (element)
ATTENTION : si vous avez dans un programme « range(a,b) », a est la
borne inférieure et b a borne supérieure. Vous ne devez surtout pas
perdre de vu que la borne inférieure est incluse, mais
que la borne supérieure est exclue.
Il est possible d’utiliser la méthode « range » pour « remplir » un tableau :
À faire vous-même 14
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
mon_tab = []
for element in range(0, 5):
mon_tab.append(element)
Créer un tableau par compréhension
Nous avons vu qu’il était possible de « remplir » un tableau en renseignant les éléments du tableau les uns après les autres :
mon_tab = [5, 8, 6, 9]
ou encore à l’aide de la méthode « append » (voir « À faire vous-même 13 »).
Il est aussi possible d’obtenir exactement le même résultat qu’au « À
faire vous-même 13 » en une seule ligne grâce à la compréhension de
tableau :
À faire vous-même 15
Quel est le contenu du tableau référencée par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
mon_tab = [p for p in range(0, 5)]
Les compréhensions de tableau permettent de rajouter une condition (if) :
À faire vous-même 16
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
l = [1, 7, 9, 15, 5, 20, 10, 8]
mon_tab = [p for p in l if p > 10]
Autre possibilité, utiliser des composants « arithmétiques » :
À faire vous-même 17
Quel est le contenu du tableau référencé par la variable mon_tab
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
l = [1, 7, 9, 15, 5, 20, 10, 8]
mon_tab = [p**2 for p in l if p < 10]
Rappel : p**2 permet d’obtenir la valeur de p élevée au carrée
Comme vous pouvez le remarquer, nous obtenons un tableau (mon_tab)
qui contient tous les éléments du tableau l élevés au carré à condition
que ces éléments de l soient inférieurs à 10.
Comme vous pouvez le constater, la compréhension de tableau permet
d’obtenir des combinaisons relativement complexes.
Travailler sur des « tableaux de tableaux »
Chaque élément d’un tableau peut être un tableau, on parle de tableau de tableau.
Voici un exemple de tableau de tableau :
m = [[1, 3, 4], [5 ,6 ,8], [2, 1, 3], [7, 8, 15]]
Le premier élément du tableau ci-dessus est bien un tableau ([1, 3,
4]), le deuxième élément est aussi un tableau ([5, 6, 8])…
Il est souvent plus pratique de présenter ces « tableaux de tableaux » comme suit :
m = [[1, 3, 4],
[5, 6, 8],
[2, 1, 3],
[7, 8, 15]]
Nous obtenons ainsi quelque chose qui ressemble beaucoup à un « objet mathématique » très utilisé : une matrice
Il est évidemment possible d’utiliser les indices de position avec
ces « tableaux de tableaux ». Pour cela nous allons considérer notre
tableau de tableaux comme une matrice, c’est à dire
en utilisant les notions de « ligne » et de « colonne ». Dans la matrice
ci-dessus :
En ce qui concerne les lignes :
1, 3, 4 constituent la première ligne
5, 6, 8 constituent la deuxième ligne
2, 1, 3 constituent la troisième ligne
7, 8, 15 constituent la quatrième ligne
En ce qui concerne les colonnes :
1, 5, 2, 7 constituent la première colonne
3, 6, 1, 8 constituent la deuxième colonne
4, 8, 3, 15 constituent la troisième colonne
Pour cibler un élément particulier de la matrice, on utilise la
notation avec « doubles crochets » : m[ligne][colonne] (sans perdre de vu
que la première ligne et la première colonne ont pour indice 0)
À faire vous-même 18
Quelle est la valeur référencée par la variable a après
l’exécution du programme ci-dessous ? (utilisez la console pour vérifier
votre réponse)
m = [[1, 3, 4],
[5, 6, 8],
[2, 1, 3],
[7, 8, 15]]
a = m[1][2]
Comme vous pouvez le constater, la variable a référence bien l’entier
situé à la 2e ligne (indice 1) et à la 3e colonne (indice 2),
c’est-à-dire 8.
À faire vous-même 19
Quel est le contenu du tableau référencé par la variable mm
après l’exécution du programme ci-dessous ? (utilisez la console pour
vérifier votre réponse)
m = [1, 2, 3]
mm = [m, m, m]
m[0] = 100
Comme vous pouvez le constater, la modification du tableau référencé
par la variable m entraine la modification du tableau référencé par la
variable mm (alors que
nous n’avons pas directement modifié le tableau référencé par mm).
Il faut donc être très prudent lors de ce genre de manipulation afin
d’éviter des modifications non désirées.
Il est possible de parcourir l’ensemble des éléments d’une matrice à l’aide d’une « double boucle for » :
À faire vous-même 20
Analysez puis testez le code suivant :
m = [[1, 3, 4],
[5, 6, 8],
[2, 1, 3],
[7, 8, 15]]
nb_colonne = 3
nb_ligne = 4
for i in range(0, nb_ligne):
for j in range(0, nb_colonne):
a = m[i][j]
print(a)
Voici ci dessous des slides sur les listes réalisés par:–Amir Charif–Lydie Du Bousquet–Aurélie Lagoutte–Julie Peyre–Florence Thiard
Les exposés sont à faire sous la forme d’une page internet de votre site. Lors de la présentation n’hésitez pas à montrer en direct ce que vous avez fait (par exemple ouvrir un fichier avec un éditeur html ; afficher le code source d’un e-mail ; utiliser les fonctions de développement d’un navigateur, etc.).
Indiquer les sources que vous avez utilisées (notamment l’origine de vos illustrations).
Vous savez documenter les fonctions à l’aide d’une «chaîne de documentation» (ou «docstring»), c’est-à-dire une chaîne de caractères placée immédiatement après l’en-tête de la fonction. Voici un tel exemple de documentation
def fact(n):
"""
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact(3)
6
>>> fact(5)
120
"""
res = 1
for i in range(2, n + 1):
res = res * i
return res
Cette documentation peut être exploitée avec la fonction help :
>>> help(fact)
Help on function fact in module __main__:
fact(n)
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact(3)
6
>>> fact(5)
120
À faire
Utilisez Pyzo pour
recopier la fonction fact avec sa docstring dans un fichier que vous nommerez exples_doctest.py,
et utiliser la fonction help au niveau de l’interpréteur.
Réaliser une telle chaîne de documentation permet
à l’utilisateur de la fonction de savoir
à quoi peut servir la fonction ;
comment il peut l’utiliser ;
et quelles conditions il doit respecter pour l’utiliser (CU).
et au programmeur de la fonction de préciser
le nombre et la nature de ses paramètres ;
la relation entre la valeur renvoyée et celle du ou des paramètres ;
ses idées avec quelques exemples.
(Tout cela bien entendu à condition que cette documentation soit rédigée
avant la réalisation du programme et non le contraire.)
Mais vous allez découvrir que cela permet davantage encore !
Utiliser le module doctest
Les exemples donnés dans une chaîne de documentation peuvent être testés à l’aide d’un module de Python nommé doctest.
À faire
Depuis l’interpréteur (shell), dans lequel la fonction fact ci-dessus est supposée chargée, tapez les deux lignes
La fonction testmod du module doctest est allée chercher dans les docstring des fonctions du module actuellement chargé, c’est-à-dire exples_doctest, tous les exemples (reconnaissables à la présence des triples chevrons >>>), et a vérifié que la fonction documentée satisfait bien ces exemples. Dans le cas présent, une seule fonction dont la documentation contient deux exemples (attempted=2) a été testée, et il n’y a eu aucun échec (failed=0).
Et si un exemple et la fonction ne sont pas d’accord ?
À faire
Modifiez le deuxième exemple, en mettant 121 à la place de 120 dans le second exemple. Chargez le fichier dans l’interpréteur (touche F5) et retapez les deux lignes
>>> import doctest
>>> doctest.testmod()
Vous devez obtenir
>>> doctest.testmod()
**********************************************************************
File "/home/eric/AP1/exples_doctest.py", line 24, in __main__.fact
Failed example:
fact(5)
Expected:
121
Got:
120
**********************************************************************
1 items had failures:
1 of 2 in __main__.fact
***Test Failed*** 1 failures.
Qu’est ce que tout cela révèle ?
Tout d’abord que les tests ont échoué et qu’il y a eu 1 échec (cf dernière ligne) et que cet échec est dû à la fonction fact (cf avant dernière ligne).
Ensuite que le test incriminé est celui concernant fact(5) pour lequel le test a obtenu (Got) 120 en exécutant la fonction fact, alors qu’il attendait (Expected) 121 selon l’exemple donné par la documentation.
Lorsqu’il y a de tels échecs, cela invite le programmeur à vérifier
son programme, … ou bien les exemples de sa documentation, comme c’est
le cas ici.
Rendre automatique les tests
Il est très facile de rendre automatique les tests et ainsi de ne plus avoir à faire appel explicitement (et manuellement) à la fonction testmod.
Il suffit pour cela d’inclure en fin de fichier les trois lignes :
if __name__ == '__main__':
import doctest
doctest.testmod()
À faire
Ajoutez ces trois lignes à la fin du fichier exple_doctest.py
et exécutez-le ! (F5)
Faites le dans le cas d’un test erroné, et dans le cas sans erreur.
Que remarquez-vous dans le cas sans erreur ?
Rendre les doctests bavards même en cas de succès
Un paramètre optionnel de la fonction testmod permet d’obtenir plus d’informations sur les tests effectués mêmes en cas de succès.
Il suffit pour cela de rajouter le paramètre ̀`verbose=True« :
doctest.testmod(verbose = True)
À faire
Faites-le !
Et observez ce que vous obtenez
avec des exemples erronés
sans exemple erroné.
Les sorties complexes
Tester les exemples des docstring avec le module doctest peut être source de déboires et de pièges. Vous allez découvrir certains d’entre eux et les remèdes qu’on peut y apporter.
Avec les listes
Supposez que vous vouliez donner un exemple qui produit la liste
des factorielles des entiers de 0 à 5.
Vous avez donc complété votre documentation en ajoutant
"""
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact(3)
6
>>> fact(5)
120
La liste des factorielles des entiers de
0 à 5
>>> [fact(n) for n in range(6)]
[1,1,2,6,24,120]
"""
Avertissement
La ligne blanche entre le deuxième exemple et la phrase qui
suit est absolument nécessaire. En son absence, la phrase sera comprise
comme faisant partie de la sortie produite par le deuxième exemple, et
le test échouera donc.
Il est clair que ce nouvel exemple est tout à fait correct.
Pourtant, si vous procédez au test vous constaterez que sur les trois exemples testés, l’un a abouti à un échec : le troisième.
À faire
Faites-le !
Quel est le problème ? Cela vient du fait que la fonction testmode effectue une comparaison litérale entre la réponse fournie par la documentation (Expected ) et celle fournie par l’interpréteur (Got).
À faire
Examinez attentivement ces deux points (Expected et Got) dans la réponse du test que vous venez d’effectuer.
Avez-vous compris ? Le problème, ce sont les espaces que l’interpréteur
place après chaque virgule dans l’énumération des éléments de la liste.
Dans la documentation, ils n’y sont pas.
Comment corriger ce point ?
C’est simple, il faut mettre des espaces entre les éléments d’une liste.
Mais ce n’est pas si simple. On peut facilement mettre plusieurs espaces,
comme ci-dessous :
"""
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact(3)
6
>>> fact(5)
120
La liste des factorielles des entiers de
0 à 5
>>> [fact(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
À faire
Faites-le ! Testez !
L’excès d’espaces provoque des erreurs. Si on ajoute, sous forme d’un commentaire la directive #doctest :
+ NORMALIZE WHITESPACE , alors le test réussit, à condition néanmoins d’avoir mis au moins une espace après chaque virgule.
"""
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact (3)
6
>>> fact (5)
120
La liste des factorielles des entiers de
0 à 5
>>> [fact (n) for n in range (6)]
... # doctest: +NORMALIZE_WHITESPACE
[1, 1, 2, 6, 24, 120]
"""
À faire
Vérifiez-le !
Avertissement
les trois petits points sous les trois chevrons sont indispensables.
Avec la directice supplémentaire +ELLIPSIS , on peut même se dispenser d’énumérer explicitement tous les éléments de la liste :
"""
paramètre n : (int) un entier
valeur renvoyée : (int) la factorielle de n.
CU : n >= 0
Exemples :
>>> fact(3)
6
>>> fact(5)
120
La liste des factorielles des entiers de
0 à 5
>>> [fact(n) for n in range(6)]
... # doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
[1, ..., 24, 120]
"""
À faire
Vérifiez-le !
Attention aux ensembles et dictionnaires
Contrairement aux listes ou tuples, les ensembles et les dictionnaires ne sont pas des
structures de données séquentielles. Il est impossible de prévoir dans quel
ordre un interpréteur Python écrira les éléments de ces structures.
Par exemple, on peut très bien avoir
>>> {'a', 'b'}
{'a', 'b'}
comme on peut avoir
>>> {'a', 'b'}
{'b', 'a'}
Il est donc difficile d’illustrer une valeur d’un de ces deux types dans un
exemple d’une docstring. Il est préférable de tester l’égalité de deux
valeurs [1] :
>>> {'a', 'b'} == {'b', 'a'}
Voici donc un exemple de ce qu’il est envisageable de placer dans une
docstring
Un dictionnaire de certaines valeurs de fact :
>>> set (n for n in range(5)) == {0, 1, 2, 3, 4}
True
À faire
Vérifiez ce point !
Avec des sorties aléatoires
Comment tester des fonctions qui produisent des valeurs aléatoires ?
Dans l’absolu, il est impossible de placer un exemple dans la docstring
donnant le résultat d’un appel à de telles fonctions puisque les valeurs
qu’elles renvoient sont imprévisibles.
Par exemple si on veut tester qu’une fonction simulant un dé à six faces
ne produit que des nombres compris entre 1 et 6, comment faire ?
On peut si on le souhaite vérifier que cette fonction ne renvoie que des nombres
compris entre 1 et 6.
from random import randrange
def de():
"""
paramètre : aucun
valeur renvoyée : (int) un nombre choisi au hasard compris entre
1 et 6.
CU : aucune
Exemple :
>>> 1 <= de() <= 6
True
"""
return randrange(1,7)
À faire
Concevez un test qui vérifie 100 fois qu’aucun nombre produit par la fonction de n’est en dehors de l’intervalle [1,6]
.
Mais un tel test ne prouve pas que jamais la fonction ne produira un nombre en dehors de
cet intervalle.
Méthodologie
Note
Pour chacun des fichiers de programmes Python que vous écrirez durant
les séances de TP, ainsi que dans la réalisation du projet de fin de
semestre, vous devrez
documenter toutes les fonctions avec une docstring donnant des exemples pertinents d’utilisation de ces fonctions
ajouter les trois lignes de code suivantes en fin de fichier :
if __name__ == « __main__ »:
import doctest
doctest.testmod()
Que fait cette fonction ? Vous ne l’avez pas écrite ou il y a longtemps…Il manque de la documentation.
Voici la même fonction documentée:
def is_even(nbr):
"""
Cette fonction teste si un nombre est pair.
L’argument nbr peut être un entier ou un nombre à virgule, si nbr est pair la fonction renvoie True, si nbr est impaire la fonction renvoie False.
"""
return nbr % 2 == 0
à faire vous même:
copier cette fonction sous Pyzo, tester la .
Puis dans la console entrer la commande
help (is_even)
vous aurez la documentation de vote fonction .
Il est important de bien commenter son programme et de documenter les fonctions, cela permet de reprendre un code que l’on a écrit il y a longtemps et cela facilite la compréhension de votre code par un autre programmeur ( par exemple en projet à plusieurs codeurs).
Aline envisage d’ouvrir un compte à la banque Argento,
mais elle veut d’abord savoir si cela sera rentable. Sur un tel compte, les
intérêts sont de 5% par an, et la banque prélève un coût fixe annuel de 11 euros.
Le capital de l’année n + 1 est donc obtenu par la formule un+1 =
un × 1.05 − 11, où un désigne le capital à l’année n.
Écrire une fonction capital(nb_annees, capital_debut) qui renvoie le capital en euros qu’Aline aurait sur un tel compte au bout de nb_annees en plaçant initialement un capital égal à capital_debut (en euros).
Écrire une fonction gagne_argent(nb_annees, capital_debut) qui renvoie True si le capital au bout de nb_annees sur un tel compte est supérieur ou égal au capital de début.
Exercice tiré de caséine université de Grenoble – proposé par Aurélie Lagoutte
Vous avez certainement utilisé cet algorithme, C’est celui que les joueurs de cartes utilisent pour organiser leurs mains. Le joueur pioche la carte qui est en haut du tas et la place (l’insère) à la bonne position dans la main. Cet algorithme se nomme le « tri par insertion ».
Pour simplifier nous allons trier une liste de 9 valeurs
[ 8, 6, 3, 9, 2, 1, 4, 5, 7 ]
pour commencer l’explication , utilisons 2 listes
A faire:
Réaliser le même schéma avec [ 5, 12, 3, 7, 4 ] sur le document Libre Office réponse joint.
Combien de comparaison? pour trier [ 8, 6, 3, 9, 2, 1, 4, 5, 7 ]
La première valeur pas de comparaison, on la prend et la pose en premier, la deuxième valeur à classer je la compare à la première ordonnée et je la pose devant ou derrière. Pour la troisième valeur , deux comparaison et ainsi de suite jusqu’à la dernière huit comparaison donc nous avons fait 1+2+3+4+5+6+7+8 comparaison soit 36 comparaison.
A faire: à vous par extension pour une liste à n éléments:
Voici une implémentation sous python avec 2 tableaux ou listes comme le graphique ci dessus
def tri_insertion(tableau):
'''cette fonction prend en argument un tableau (tableau), et le trie avec la méthode de tri par insertion, elle renvoie le tableau trié (resultat)
exemple:
tri_insertion([22,8,32,1,69])
>>> [1,8,22,32,69]
tri_insertion([18,41,7,2,14])
>>> [2,7,14,18,41]'''
resultat=[]
longueur = len(tableau)
while len(resultat) < longueur:
'''tant que la taille du résultat n'est pas le même que celui du tableau initial'''
for indice in range(0,longueur):
compteur = 0
placer = True
if resultat == []:
resultat.append(tableau[0])
del tableau[0]
for valeur_resultat in resultat:
if tableau == []:
return resultat
if valeur_resultat < tableau[0]:
compteur += 1
elif placer:
placer = False
resultat.insert(compteur, tableau[0])
del tableau[0]
compteur = 0
if placer:
resultat.append(tableau[0])
del tableau[0]
voici l’algorithme du tri par insertion ( ici une seule liste )
PROCEDURE tri_Insertion ( Tableau a[1:n])
POUR i VARIANT DE 2 A n FAIRE
INSERER a[i] à sa place dans a[1:i-1];
FIN PROCEDURE;
en python à essayer
def tri_insertion(tableau):
print(tab)#affiche la liste tab pour visualiser l'algo
for i in range(1,len(tableau)):
en_cours = tableau[i]
j = i
#décalage des éléments du tableau }
while j>0 and tableau[j-1]>en_cours:
tableau[j]=tableau[j-1]
j = j-1
#on insère l'élément à sa place
tableau[j]=en_cours
Pour simplifier nous allons trier une liste de 9 valeurs
[ 8, 6, 3, 9, 2, 1, 4, 5, 7 ]
pour commencer l’explication , utilisons 2 listes
A faire: sur le document réponse Libre Office.
Réaliser le même schéma avec [ 5, 12, 3, 7, 4 ] sur le document réponse Libre Office. En fin de document vous pouvez découper les numéros pour faire une simulation à la main.
Combien de comparaison? pour trier [ 8, 6, 3, 9, 2, 1, 4, 5, 7 ]
pour sélectionner l’élément le plus petit on liste les 9 valeurs et on fait 8 comparaisons, pour le deuxième on fait 7 comparaisons, pour le troisième 6 comparaisons et ainsi de suite. D’où nombre de comparaison= 8+7+6+….+1=36.
Par extension si notre liste est constituée de n valeurs, le nombre de comparaison = (n-1)+(n-2)+(n-3)+ …..+3+2+1 en factorisant nombre de comparaison=n*(n-1) /2 soit n²/2-n/2 .
On dit que l’algorithme de tri par sélection a donc une complexité en O(n²). On parle aussi de complexité quadratique.
Voici une implémentation sous python avec 2 tableaux ou listes comme le graphique ci dessus
def tri_selection(tableau):
'''tri d'un tableau, l'argument tableau est un tableau ou liste, la fonction renvoie un autre tableau ou liste resultat'''
resultat = []
longueur = len(tableau)
while len(resultat) != longueur:
minimum = tableau[0]
for i in range(1, len(tableau)):
if minimum > tableau[i]:
minimum = tableau[i]
resultat.append(minimum)
tableau.remove(minimum)
return resultat
voici l’algorithme du tri par sélection ( ici une seule liste )
PROCEDURE tri_Selection ( Tableau a[1:n])
POUR i VARIANT DE 1 A (n – 1) FAIRE
TROUVER [j] LE PLUS PETIT ELEMENT DE [i + 1:n];
ECHANGER [j] ET [i];
FIN PROCEDURE;
en python à essayer
def tri_selection(tab):
print(tab)
for i in range(len(tab)):#boucle sur toute la liste
# Trouver le min
min = i
for j in range(i+1, len(tab)):
if tab[min] > tab[j]:
min = j
tmp = tab[i]
print('tmp',tmp)#affiche tmp pour visualiser l'algo
tab[i] = tab[min]
print ('tab1',tab)#affiche la liste tab pour visualiser l'algo
tab[min] = tmp
print('tab2',tab)#affiche la liste tab pour visualiser l'algo
return tab
# Programme principale pour tester le code ci-dessus
tab = [98, 22, 15, 32, 2, 74, 63, 70]#changer les valeurs de la liste pour un autre essai
tri_selection(tab)
print ("Le tableau trié est:")
print (tab)