Instruction Répétitive 1 CPES 1re année 2016-2017 PSL Informatique Exercices sur les instructions répétitives Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 1 Les instructions répétitives (boucles) permettent de répéter un bloc d’instructions. La syntaxe d’une instruction répétitive est : while expression_booleenne : BlocInstruction Exercice 1 Soit le programme Python suivant : i=int(input("debut : ")) j=int(input("fin : ")) while (i!=j): if (i%7==0): print(i, " est multiple de 7") i+=1 1. Que fait ce programme dans le cas général ? 2. Que se passe-t-il si on entre une valeur de i strictement plus grande que j ? Comment pourrait-on améliorer ce programme ? Correction 1. Le programme fait saisir deux variables entières i et j. Puis affiche tous les multiples de 7 entre i et j (j exclus et si i est inférieur à j). 2. Si i est supérieur à j le programme va tourner indéfiniment (la boucle tant que s’exécutera tant que i est supérieur à j, ce qui sera toujours le cas). Pour améliorer le programme, il faut changer la condition et mettre tant que i < j. Exercice 2 Étant donnée f (x) = x3 − 3x2 + 1, une fonction continue et strictement croissante sur l’intervalle [2; 3], l’algorithme ci-dessous permet de déterminer la valeur approchée de x telle que f (x) = 0 par une méthode dichotomique avec une précision . 1. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine 2 Instruction répétitive VARIABLES precision EST_DU_TYPE NOMBRE a,b,m EST_DU_TYPE NOMBRE f_m,f_b EST_DU_TYPE NOMBRE DEBUT_ALGORITHME LIRE precision a <- 2 b <- 3 TANT_QUE (b-a > precision) FAIRE DEBUT_TANT_QUE m <- (a+b)/2 f_m <- (m**3) - 3*(m**2) + 1 f_b <- (b**3) - 3*(b**2) + 1 SI (f_m*f_b > 0) ALORS DEBUT_ALORS b <- m FIN_ALORS SINON DEBUT_SINON a <- m FIN_SINON FIN_TANT_QUE ECRIRE a ECRIRE " <= solution <= " ECRIRE b FIN_ALGORITHME Programmer en Python cet algorithme. precision=float(input()) a = 2 b = 3 while (b-a > precision): m=(a+b)/2 f_m=(m**3) - 3*(m**2) + 1 f_b = (b**3) - 3*(b**2) + 1 if (f_m*f_b > 0): b = m else: a = m print(a, ’<= solution <=’, b) >>> (executing lines 1 to 12 of "<tmp 1>") 0.00001 2.8793792724609375 <= solution <= 2.8793869018554688 Instruction Répétitive 3 Exercice 3 Écrire un programme en Python qui saisit un réel x ≥ 0 et un entier n ≥ 0, et affiche la valeur de xn (sans utiliser l’opérateur puissance). Tester votre programme pour les valeurs suivantes : x = 4 n = 3, x = 5 n = 0, x = 0 n = 0. Correction x=int(input(’entrez x’)) n=int(input(’entrez n’)) resul=1 while n>0: resul=resul*x n-=1 print(resul) Exercice 4 ∗ Soit pour tout n ∈ N , Sn = n X 1 , écrire un programme déterminant la plus petite valeur de k k=1 n pour laquelle Sn > A, A étant un réel entré par l’utilisateur. N’essayez pas votre programme avec des valeurs de A supérieures à 20. A=float(input("A = ")) n=1 un=1 while un <= A : n+=1 un = un + 1/n print(n,un) Quand A = 10, n = 12367 et S1 2367 = 10.000043008275778 Exercice 5 Soit la suite définie par u0 = 0, et pour tout n ∈ N, un+1 = √ 3un + 4. 1. Écrire un programme demandant à l’utilisateur un entier n et affichant tous les termes de la suite jusqu’à un . 2. Modifier votre programme pour qu’il affiche le plus petit entier n pour lequel un > 4−, où > 0. Que trouve-t-on pour = 10−8 = 1.e − 8 ? Exercice 6 Écrire un algorithme en pseudo-langage puis en Python, qui saisit un entier (supposé strictement positif), affiche la somme de tous ses diviseurs stricts et précise si ce nombre est premier. Par exemple, si l’on saisit 8, il affiche 7 (car somme de ses diviseurs stricts qui sont 1, 2 et 4). 4 Instruction répétitive Correction VARIABLES n EST_DU_TYPE NOMBRE // entier saisi par l’utilisateur d EST_DU_TYPE NOMBRE // diviseur somme EST_DU_TYPE NOMBRE DEBUT_ALGORITHME LIRE n d <- 1 somme <- 0 TANT_QUE (d<n) FAIRE DEBUT_TANT_QUE SI ((n%d)==0) ALORS DEBUT_ALORS somme <- somme+d FIN_ALORS d <- d+1 FIN_TANT_QUE SI ((somme==1) ET (n!=1)) ALORS DEBUT_ALORS ECRIRE "Ce nombre est premier." FIN_ALORS SINON DEBUT_SINON ECRIRE "La somme des diviseurs est :" ECRIRE somme FIN_SINON FIN_ALGORITHME Exemples d’exécution : Exemple d’exécution avec n=5 d <- 2 somme = 1 (d<n): n%d ==1 d<-3 (d<n): n%d ==2 d<-4 (d<n): n%d ==1 d<-5 (d==n) on sort du tant que somme==1 on affiche "Ce nombre est premier" Exemples d’exécution avec n=8 d = 2 somme = 1 (d<n): n%d ==0 somme=1+2 Instruction Répétitive 5 d=3 (d<n): n%d ==2 d=4 (d<n): n%d ==0 somme=3+4 d=5 (d<n): n%d ==3 d=6 (d<n): n%d ==2 d=7 (d<n): n%d ==1 d=8 (d==n) on sort du tant que somme!=1 on affiche "La somme des diviseurs est 7 Autre solution : VARIABLES k EST_DU_TYPE NOMBRE // compteur s EST_DU_TYPE NOMBRE // somme des diviseurs n EST_DU_TYPE NOMBRE // entier saisi par l’utilisateur DEBUT_ALGORITHME LIRE n k <- 1 s <- 0 TANT_QUE (k<n) FAIRE DEBUT_TANT_QUE SI ((n/k)==PARTIE_ENTIERE(n/k)) ALORS DEBUT_ALORS // Si k est un diviseur de n s <- s+k FIN_ALORS k <- k+1 FIN_TANT_QUE ECRIRE s SI ((s==1) et (n!=1)) ALORS DEBUT_ALORS ECRIRE n ECRIRE " est premier." FIN_ALORS SINON DEBUT_SINON ECRIRE "La somme des diviseurs est " ECRIRE s FIN_SINON FIN_ALGORITHME NB (pour nous uniquement) : dans le logiciel d’AlgoBox, l’instruction PARTIE_ENTIERE est : floor(x). 6 Instruction répétitive Exercice 7 Un entier est dit parfait s’il est égal à la somme de ses diviseurs stricts (6 par exemple est parfait). Écrire un algorithme qui saisit un entier n (supposé strictement positif) et affiche tous les nombres parfaits inférieurs ou égaux à n. Correction VARIABLES n EST_DU_TYPE NOMBRE d EST_DU_TYPE NOMBRE somme EST_DU_TYPE NOMBRE DEBUT_ALGORITHME LIRE n TANT_QUE (n>1) FAIRE DEBUT_TANT_QUE d <- 1 somme <- 0 TANT_QUE (d<n) FAIRE DEBUT_TANT_QUE SI ((n%d)==0) ALORS // Si d est un diviseur de n DEBUT_ALORS somme <- somme+d FIN_ALORS d <- d+1 FIN_TANT_QUE SI (somme==n) ALORS DEBUT_ALORS ECRIRE somme FIN_ALORS n <- n-1 FIN_TANT_QUE FIN_ALGORITHME Nombres parfaits : 6, 28, 496, 8128 ... A tester en TP. Autre solution : VARIABLES n EST_DU_TYPE i EST_DU_TYPE s EST_DU_TYPE k EST_DU_TYPE NOMBRE NOMBRE NOMBRE NOMBRE // // // // DEBUT_ALGORITHME LIRE n i <- 1 TANT_QUE (i<=n) FAIRE Entier saisi par l’utilisateur compteur somme des diviseurs compteur Instruction Répétitive 7 DEBUT_TANT_QUE s <- 0 k <- 1 TANT_QUE (k<i) FAIRE DEBUT_TANT_QUE SI ((i/k)==PARTIE_ENTIERE(i/k)) ALORS DEBUT_ALORS // Si k diviseur de i s <- s+k FIN_ALORS k <- k+1 FIN_TANT_QUE SI (s==i) ALORS DEBUT_ALORS ECRIRE s FIN_ALORS i <- i+1 FIN_TANT_QUE FIN_ALGORITHME Exercice 8 A l’aide de 2 boucles TANT_QUE emboîtées, écrire un algorithme qui affiche : 1 1 1 1 2 3 4 5 3 5 7 9 4 7 10 13 5 9 13 17 Correction On remarque que la ligne 1 correspond à 5 entiers dont la différence deux à deux vaut 1, la ligne 2 correspond à 5 entiers dont la différence deux à deux vaut 2, la ligne 3 correspond à 5 entiers dont la différence deux à deux vaut 3, etc. Dans l’algorithme on utilise donc 3 variables, nbLignes qui va représenter le numéro de la ligne courante, i qui correspond à l’entier à afficher et nbCol qui correspond au numéro de la colonne courante. VARIABLES nbLignes EST_DU_TYPE NOMBRE // numéro de la ligne courante i EST_DU_TYPE NOMBRE // entier à afficher nbCol EST_DU_TYPE NOMBRE // numéro de la colonne courante DEBUT_ALGORITHME nbLignes <- 1 TANT_QUE (nbLignes<=4) FAIRE DEBUT_TANT_QUE nbCol <- 1 i <- 1 8 Instruction répétitive TANT_QUE (nbCol<=5) FAIRE DEBUT_TANT_QUE ECRIRE i ECRIRE " " i <- i+nbLignes nbCol <- nbCol+1 FIN_TANT_QUE ECRIRE "Saut-de-ligne" nbLignes <- nbLignes+1 FIN_TANT_QUE FIN_ALGORITHME Exercice 9 Écrire un algorithme qui saisit un entier strictement positif n, puis n entiers, et qui vérifie si la suite des n entiers saisis est triée de façon croissante. Par exemple, si la valeur saisie pour n est 7 et les 7 valeurs saisies sont : -1, 3, 7, 8, 11, 234, 300, le programme affichera "les 7 valeurs sont triées de façon croissante", alors que le programme affichera "les 7 valeurs ne sont pas triées" si les entiers saisis sont : 1, 2, 7, -2, 4, 5, 200. Correction VARIABLES n EST_DU_TYPE i EST_DU_TYPE p EST_DU_TYPE c EST_DU_TYPE b EST_DU_TYPE NOMBRE NOMBRE // compteur NOMBRE // nombre précédemment saisi NOMBRE // nombre courant saisi BOOLEEN // vrai tant que la suite est triée DEBUT_ALGORITHME n <- 0 TANT_QUE (n<=0) FAIRE // pour forcer l’utilisateur à saisir un entier positif DEBUT_TANT_QUE LIRE n FIN_TANT_QUE LIRE c i <- 1 // On a déjà saisi un entier - reste à en saisir (n-1) b <- VRAI TANT_QUE (i<n) FAIRE DEBUT_TANT_QUE p <- c // on stocke l’entier précédemment saisi LIRE c SI (p>c) ALORS // si l’utilisateur a saisi un entier inférieur à l’entier précédemment saisi DEBUT_ALORS b <- FAUX // Les valeurs ne sont pas ordonnées Instruction Répétitive 9 de manière croissante. FIN_ALORS i <- i+1 FIN_TANT_QUE ECRIRE "Les " ECRIRE n SI (b==VRAI) ALORS DEBUT_ALORS ECRIRE " valeurs sont triées de façon croissante." FIN_ALORS SINON DEBUT_SINON ECRIRE " valeurs ne sont pas triées." FIN_SINON FIN_ALGORITHME Exercice 10 Écrire un algorithme qui saisit un entier strictement positif n, puis n entiers strictement positifs, et qui vérifie si parmi les n entiers saisis, la somme des entiers pairs est égale à la somme des entiers impairs. Le programme doit refuser les valeurs négatives ou nulles. Par exemple, si la valeur saisie pour n est 5 et les 5 valeurs saisies sont 2, 3, 2, 3, 2, l’algorithme affichera "la somme des nombres pairs est égale à la somme des nombre impairs", alors que l’algorithme affichera "la somme des nombres pairs n’est pas égale à la somme des nombres impairs" si les valeurs saisies sont 2, 3, 4, 3, 1. Si la valeur saisie pour n (ou une des n valeurs) est par exemple -2, l’algorithme demandera à nouveau d’insérer une valeur, jusqu’à ce que celle-ci soit strictement positive. Correction VARIABLES n EST_DU_TYPE NOMBRE s_i EST_DU_TYPE NOMBRE // sommes de entiers impairs s_p EST_DU_TYPE NOMBRE // sommes de entiers pairs i EST_DU_TYPE NOMBRE // compteur e EST_DU_TYPE NOMBRE // entier saisi DEBUT_ALGORITHME n <- 0 s_i <- 0 s_p <- 0 TANT_QUE (n<=0) FAIRE DEBUT_TANT_QUE ECRIRE "Saisir une valeur positive non nulle :" LIRE n FIN_TANT_QUE i <- 0 10 Instruction répétitive TANT_QUE (i<n) FAIRE DEBUT_TANT_QUE e <- 0 TANT_QUE (e<=0) FAIRE DEBUT_TANT_QUE ECRIRE "Saisir un entier positif non nul :" LIRE e FIN_TANT_QUE SI ((e%2)==0) ALORS // si e est pair DEBUT_ALORS s_p <- s_p+e FIN_ALORS SINON DEBUT_SINON s_i <- s_i+e FIN_SINON i <- i+1 FIN_TANT_QUE SI (s_i==s_p) ALORS DEBUT_ALORS ECRIRE "La somme des nombres pairs est égale à la somme des nombre impairs." FIN_ALORS SINON DEBUT_SINON ECRIRE "La somme des nombres pairs n’est pas égale à la somme des nombres impairs." FIN_SINON FIN_ALGORITHME Les chaînes de caractères en Python 11 CPES 1re année 2016-2017 PSL Informatique Les chaînes de caractères en Python Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 2 Exercice 1 Décrire ce que fait le programme Python ci-dessous : print("Entrer une chaine de caracteres :") ch=input() i=0 l=len(ch) chNew="" while i<l: if (ch[i]=="," or ch[i]==";" or ch[i]=="."): chNew=chNew+"p" else: chNew=chNew+ch[i] i+=1 print(chNew) Lorsque l’utilisateur saisit au clavier : En Python, les caractères de ponctuation ;,. sont faciles à manipuler. indiquer ce que va faire ce programme. Écrire une nouvelle version beaucoup plus simple de ce programme Python en utilisant des méthodes de chaînes. Correction Ce programme Python lit une chaîne de caractères ch, et affiche la chaîne obtenue en remplaçant les signes de ponctuations ",", ";" et "." par le caractère "p". Le programme affiche donc : En Pythonp les caractères de ponctuation ppp sont faciles à manipulerp Avec les méthodes de chaînes, on obtient : 2. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine 12 Les chaînes de caractères en Python print("Entrer une chaine de caracteres :") ch=input() ch=ch.replace(",","p") ch=ch.replace(";","p") ch=ch.replace(".","p") print(ch) Ou même : print("Entrer une chaine de caracteres :") ch=input() ch=ch.replace(",","p").replace(";","p").replace(".","p") print(ch) Exercice 2 1. Écrire un programme Python qui lit une chaîne de caractères s, affiche sa longueur, puis affiche s avec tous les espaces du début, intermédiaires et de la fin, supprimées. 2. Écrire un nouveau programme Python qui permet, non pas simplement d’afficher s, mais de modifier s en enlevant tous les espaces du début, intermédiaires et de la fin. Correction print("Entrer une chaine de caracteres :") ch=input() print("La longueur de la chaine est : ", len(ch)) print(ch.replace(" ","")) print("Entrer une chaine de caracteres :") ch=input() print("La longueur de la chaine est : ", len(ch)) ch=ch.replace(" ","") print(ch) Exercice 3 Écrire un algorithme en pseudo-code, puis un programme Python, qui lit une chaîne de caractères, puis lit une ou plusieurs valeurs entières et qui, pour chacune de ces valeurs v, remplace le caractère situé en position v par le caractère ’?’. Ce programme se termine par l’affichage de la nouvelle chaîne. Attention : il faut bien vérifier que les valeurs v correspondent à des positions valides pour la chaîne de caractères lue. Correction print("Entrer une chaîne de caractères") s=input() l=len(s) Les chaînes de caractères en Python 13 rep=’o’ while (rep==’o’): print("Donner une valeur entière") v=int(input()) if (v>=0 and v<l): s=s[:v]+"?"+s[v+1:] else: print(v," n’est pas une position valide car n’appartient pas à [0,", l,"]", sep=’’) print("Voulez-vous continuer ? (o/n)") rep=input() print(s) Exercice 4 Écrire un algorithme en pseudo-code, puis un programme Python, qui lit une chaîne de caractères et teste si c’est un palindrome. Un palindrome est une chaîne de caractères dont l’ordre des lettres reste le même qu’on la lise de la gauche vers la droite ou de la droite vers la gauche. C’est par exemple le cas de la chaîne "kayak". On supposera que la chaîne de caractères lue ne contient que des caractères minuscules non accentués, et qu’elle ne contient ni espace, ni caractère de ponctuation. Correction print("Entrer une chaîne de caractères") ch=input() debut=0 fin=len(ch)-1 while ((debut<fin) and (ch[debut]==ch[fin])): debut=debut+1 fin=fin-1 if (debut >= fin): print(ch, " est un palindrome") else: print(ch, " n’est pas un palindrome") Autre programme : print("Entrer une chaîne de caractères") ch=input() if (ch == ch[::-1]): print(ch, " est un palindrome") else: print(ch, " n’est pas un palindrome") 14 Les chaînes de caractères en Python Exercice 5 Écrire un programme Python qui lit une chaîne de caractères ch et qui affiche la chaîne de caractères obtenue en ignorant les mots de longueur inférieure ou égale à 3 dans ch. Par exemple, si la chaîne lue est "bonjour les amies !" l’algorithme affichera "bonjour amies". On définira un mot comme toute suite de caractères quelconques ne contenant pas d’espace. Correction print("Entrer une chaîne de caractères") ch=input() i=0 while (i<len(ch)): mot="" while ((i<len(ch)) and (ch[i] != " ")): mot = mot + ch[i] i = i+1 if (len(mot) >= 3): print(mot,end=" ") i += 1 Exercice 6 Écrire un programme Python qui lit une chaîne de caractères et qui affiche cette chaîne avec les suites de caractères identiques remplacées par un seul caractère. Par exemple, on donnera la chaîne "abbcdebbb" et votre programme devra afficher "abcdeb." Correction print("Entrer une chaîne de caractères") ch=input() resul=ch[0] i=1 while i<len(ch): if (ch[i-1]!=ch[i]): resul = resul + ch[i] i+=1 print(resul) Exercice 7 Écrire un programme Python qui lit deux chaînes de caractères ch1 et ch2, et qui détermine un entier N tel que ch1 est égale à N concaténations successives de ch2 avec elle-même. Si cette propriété est satisfaite le programme affichera N, dans le cas contraire, le programme affichera "non". On suppose que l’utilisateur saisira toujours des chaînes de caractères ch1 et ch2 non vides ne contenant pas d’espace. Le tableau ci-dessous donne des exemples de valeurs que le programme doit afficher. Les chaînes de caractères en Python 15 ch1 ch2 valeur affichée "ababab" "ab" 3 "ab" "ab" 1 "abhabab" "ab" non "aaaa" "aa" 2 "aaa" "aa" non "aaa" "a" 3 Correction Une première solution très simple : ch1 = input("ch1=") ch2 = input("ch2=") print ("oui" if ch1 == ch2*(len(ch1)//len(ch2)) else "non") Et une deuxième qui construit la chaîne à tester : ch1 = input("ch1=") ch2 = input("ch2=") N = len(ch1)//len(ch2) ch = "" i = 0 while i<N: ch= ch + ch2 i += 1 print ("oui" if ch1 == ch else "non") Exercice 8 Écrire un programme Python qui saisit une chaîne de caractères ch et qui affiche la liste des mots de ch ainsi que les positions de début de chacun des mots dans ch (chaque mot pouvant se répéter plusieurs fois). Par exemple, pour ch=" ab cda fg ab fg cda h cda ", le programme doit afficher : "ab" 1, 11 "cda" 4, 19, 25 "fg" 8, 16 "h" 23 Attention, plusieurs espaces peuvent se trouver entre deux mots consécutifs, ainsi qu’avant le premier mot et après le dernier mot. Exercice 9 : Écrire en Python un programme qui lit une chaîne de caractères (supposée sans espace et de longueur au moins égale à 3) et l’affiche sous la forme d’un N. Si l’on saisit par exemple "abcde", alors le programme doit afficher : 16 Les chaînes de caractères en Python a a bb b c c c d dd e e Correction str = input("chaine : ") lg = len(str) str_a_afficher=’’ i=0 while (i<lg): if i == 0 or i == lg-1: str_a_afficher = (str[i]+’ ’ * (lg-2)+str[i]) else: str_a_afficher = (str[i] + ’ ’ * (i-1) + str[i] + ’ ’ * (lg-2-i) + str[i]) i+=1 print(str_a_afficher) ou encore str = input("chaine : ") lg = len(str) ligne=0 while (ligne < lg): col=0 while (col < lg): if (col == 0 or col == lg-1 or ligne == col): print(str[ligne], end=’’) else: print (’ ’, end=’’) col+=1 print() ligne+=1 Exercice 10 : Formater l’affichage des nombres L’insertion d’une valeur numérique x dans une chaîne de caractères ch à l’indice p se fait simplement comme suit : ch[:p] + str(x) + ch[p:] Dans cette expression, on utilise la convertion explicite du type de x en string, la concaténation et le slicing. Par exemple, exécuter les instructions suivantes : x=1/3 ch=’bonjour’ ch=ch[0:2]+str(x)+ch[2:] print(ch) Les chaînes de caractères en Python 17 Il n’est alors pas possible de paramétrer finement le format obtenu pour la valeur numérique (le nombre de chiffres après la virgule par exemple). Pour réaliser un paramétrage plus fin, il existe en Python la méthode de chaîne appelée format. La syntaxe pour appliquer la méthode format à la chaîne ch est ch.format(arguments) Dans l’exemple précédent, pour obtenir le même résultat, on peut exécuter l’affectation ch=’bo{}njour’.format(1/3) La méthode format remplace dans une chaîne de caractères les symboles {} par l’argument donné entre parenthèses. Il existe différentes options d’affichage des nombres : — {:.4f} : écriture en virgule flottante, fixe à 4 le nombre de chiffres après la virgule. — {:.5e} : écriture en notation scientifique, fixe à 5 le nombre de chiffres après la virgule. — {:<15.2e} : fixe la longueur de la chaîne (elle est remplie par des espaces), et justifie à gauche. Le 2e a la même signification que plus haut. — {:>15.2e} : fixe la longueur de la chaîne, et justifie à droite. — {:^15.2e} : fixe la longueur de la chaîne, centre. 1. (Dans l’interpréteur) Exécuter print(’bo{:.2f}njo{}ur’.format(1/3,2/7)) puis essayez les différents formats d’affichage. 2. Ecrire un programme affichant toutes les valeurs de la suite un définie par la récurrence u0 = 1 et pour tout n > 0, un+1 = sin(un ) jusqu’à obtenir une valeur inférieure ou égale à 2.10−2 . L’affichage devra être fait sous le format un = v où n et v sont remplacées par leur valeur. import math u=1 n=0 while u>2*10**(-2): print(’u{}={}’.format(n,u)) u=math.sin(u) n+=1 Fin pour n=7492 18 Modules externes et projet de Casino CPES 1re année 2016-2017 PSL Informatique Modules externes et projet de Casino Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 3 Les modules externes Les modules externes, appelés également bibliothèques (de library en anglais), sont des programmes Python qui contiennent des fonctions et méthodes qu’il est possible d’appeler dans vos programmes. Les développeurs de Python ont rendu disponibles de nombreux modules. La plupart de ces modules sont disponibles dans les versions standards de Python. Voici une liste non exhaustive des modules utiles : — math : contient des fonctions et constantes math de base (sin, cos, exp, logarithme, racine carrée, puissance, π...) ; — os : contient des fonctions et constantes permettant d’interagir avec le système d’exploitation ; — random : contient des fonctions et constantes permettant de générer des nombres aléatoires ; — time : permet d’accéder à l’heure de l’ordinateur et aux fonctions gérant le temps ; — calendar : fonctions de calendrier ; — numpy : algèbre linéaire, calcul numérique. Ces modules ne sont pas immédiatement accessibles. Pour appeler n’importe quelle fonction d’un module (par exemple le module random) dans votre programme Python, il faut avoir au préalable importé ce module grâce à l’instruction : import random Il est possible d’obtenir de l’aide sur un module. Après avoir importé le module, il suffit d’exécuter la commande : help(nomModule) Si on veut connaître la liste des fonctions/méthodes/constantes incluses dans un module, on peut utiliser la commande dir : dir(nomModule) Vous pouvez alors appeler n’importe laquelle des fonctions incluses dans ce module. Et par exemple si on veut générer aléatoirement un nombre entier compris entre 2 et 19, il suffit d’exécuter : random.randint(2,19) La forme générale d’un appel de fonction d’un module préalablement importé est donc : 3. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine Modules externes et projet de Casino 19 import nomModule nomModule.nomFonction(...) En effet, l’instruction import nomModule crée ce que l’on appelle un espace de nom appelé nomModule, contenant les variables et les fonctions du module. Quand on appelle nomModule.nomFonction(...), on précise à Python qu’il faut exécuter la fonction de nom nomFonction contenue dans l’espace de noms nomModule. Cela signifie aussi que dans une autre partie de votre programme, vous pourriez utiliser l’identificateur nomFonction sans qu’il y ait de confusion (nomFonction 6= nomModule.nomFonction). Il existe un autre moyen, qui ne procède pas de la même façon, d’importer une fonction particulière d’un module : from nomModule import nomFonction Et pour appeler cette fonction, il suffira alors d’utiliser son nom (sans rappeler le nom du module en préfixe). Par exemple, from random import randint randint(2,19) Dans ce cas, la fonction randint() du module random a été « chargée » dans l’interpréteur au même plan que toutes les fonctions existantes, comme print() par exemple : print() et randint() appartiennent alors au même espace de noms. De cette façon, on peut également importer toutes les fonctions d’un module avec l’instruction suivante : from nomModule import * Attention si, avec cette méthode, on importe des fonctions portant le même nom provenant de modules différents, c’est la dernière fonction du dernier module importé qui sera alors la seule accessible. Exercice 1 1. Écrire un programme Python qui permet de calculer et écrire le cosinus de π/2 (module math). 2. Écrire un programme Python qui permet d’écrire une série de 10 nombres réels aléatoires compris entre 10 et 50 (inclus) avec 1 seconde d’intervalle entre chaque écriture (modules random et time). 3. Écrire un programme Python qui permet de déterminer votre jour de naissance (module calendar). Correction 1. import math print(math.cos(math.pi/2)) 20 Modules externes et projet de Casino 2. import time import random cpt=0 while cpt<10: print(random.uniform(10,50)) cpt+=1 time.sleep(1) 3. import calendar j=calendar.weekday(1997,8,14) print(calendar.day_name[j]) Exercice 2 : évaluation de π par la méthode de Monte-Carlo Soit un cercle de rayon r = 1 inscrit dans un carré de coté l = 2. L’aire du carré vaut 4 et l’aire du cercle vaut π. En choisissant N points aléatoires (à l’aide d’une distribution uniforme) à l’intérieur du carré, la probabilité que chacun de ces points se trouve aussi dans le cercle est p= π aire du cercle = aire du carré 4 Soit n, le nombre de points tirés aléatoirement se trouvant effectivement dans le cercle, on a: p= π n = N 4 d’où n N Déterminer une approximation de π par cette méthode. Pour cela, on procède en N itérations : à chaque itération, choisir aléatoirement les coordonnées d’un point entre -1 et 1 (fonction uniform() du module random), calculer la distance entre ce point et le centre du cercle, déterminer si cette distance est inférieure au rayon du cercle égal à 1, et si c’est le cas, incrémenter le compteur n de 1. Quelle est la qualité de l’approximation de π pour N = 50, N = 500, N = 5000 et N = 50 000 ? π =4× Correction import random import math print("Donner N:") N=int(input()) n=0 i=0 while (i<N): abs=random.uniform(-1,1) ord=random.uniform(-1,1) d=math.sqrt(math.pow(abs,2)+math.pow(ord,2)) if d<=1: n+=1 Modules externes et projet de Casino 21 i += 1 print("La valeur exacte de pi est :", math.pi) print("La valeur approximée de pi avec", N,"points est :", 4*n/N) Exercice 3 : à vous de jouer ! Écrire un programme de jeu de roulette (très simplifié) dans lequel le joueur peut miser une certaine somme sur un numéro et gagner ou perdre de l’argent si ce numéro est tiré aléatoirement. Le joueur peut enchainer plusieurs parties mais, il est contraint de s’arrêter s’il ne lui reste plus d’argent ! Voici la règle du jeu : Le joueur mise une certaine somme sur un numéro compris entre 0 et 49 (50 numéros en tout) en déposant cette somme sur le numéro choisi sur la table de jeu : il donne donc sa mise au croupier. La roulette est constituée de 50 cases allant de 0 à 49. Les numéros pairs sont de couleur noire, les numéros impairs sont de couleur rouge. Le croupier lance la roulette, lâche la bille et quand la roulette s’arrête, relève le numéro de la case dans laquelle la bille s’est arrêtée. Le numéro sur lequel s’est arrêtée la bille est, naturellement, le numéro gagnant. Si le numéro gagnant est celui sur lequel le joueur a misé (probabilité de 1/50, plutôt faible), le croupier lui remet 3 fois la somme misée. Dans le cas contraire, si le numéro gagnant a la même couleur que celui sur lequel le joueur a misé, le croupier lui remet 1,5 fois la somme misée ; sinon, lorsque le joueur a misé sur le mauvais numéro de mauvaise couleur, le joueur perd définitivement sa mise. Écrire dans un premier temps en pseudo-langage l’algorithme conforme à la règle du jeu. Ensuite, traduire cet algorithme en Python. Dans votre programme, il faut lire différentes valeurs (et vérifier leur cohérence vis-à-vis des valeurs attendues) : le budget initial du joueur, le numéro choisi par le joueur, le fait qu’il souhaite ou non continuer de jouer. Remarque : avec cette règle du jeu, si le joueur mise sur la bonne couleur mais pas le bon numéro, son bénéfice est de 50% de la somme misée. Au bout de nombreuses parties, on risque d’arriver à des nombres flottants avec beaucoup de chiffres après la virgule. Alors autant arrondir au nombre supérieur. Ainsi, si le joueur mise 3 euros sur la bonne couleur mais pas le bon numéro, il gagne 2 euros et le croupier lui rend 3 + 2 = 5 euros. Pour cela, on va utiliser une fonction du module math nommée ceil. Correction import math import random budgetInit=int(input("Budget Initial (en euros) : ")) if (budgetInit > 0): budget=budgetInit jouer=True while jouer: numero=int(input("Choisissez un chiffre compris entre 0 et 49 : ")) while (numero<0 or numero>49): 22 Modules externes et projet de Casino print("Vous devez choisir un chiffre compris entre 0 et 49 !") numero=int(input("Choisissez un chiffre compris entre 0 et 49 : ")) print("Votre mise (comprise entre 1 et ",budget,") : ",end="") mise=int(input()) while (mise > budget): print("Vous n’avez plus assez d’argent ! Nouvelle mise ( <",budget,") : ") mise=int(input()) budget-=mise bille=random.randrange(0,49) print("Numero gagnant : ",bille) if (bille == numero): budget+=3*mise print("Vous gagnez :", 3*mise, " et votre budget est de", budget) elif (bille%2 == numero%2): budget+=math.ceil(1.5*mise) print("Vous gagnez",math.ceil(1.5*mise), "et votre budget est de",budget) else: print("Vous perdez", mise, "euros et il vous reste", budget) rep=input("Continuez (O/N) ? ") if (rep==’N’ or budget==0): jouer=False if (budgetInit < budget): print("Vous avez gagne", budget-budgetInit, "euros.") else: if (budget == 0): print("Vous ne pouvez pas rejouer ! Il ne vous reste plus rien !!") else: print("Vous avez perdu", budgetInit-budget, "euros.") else: print("Vous ne pouvez pas jouer !") Fonctions 23 CPES 1re année 2016-2017 PSL Informatique Fonctions Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 4 Exercice 1 : utilisation de fonctions Python existantes La liste des fonctions Python existantes (dont print() et input() par exemple) est disponible à l’adresse suivante : https://docs.Python.org/3/library/functions.html Dans l’interpréteur de commandes taper les instructions suivantes : abs(-5) help(abs) max(5,12) help(max) min(5,12) help(min) Exercice 2 Écrire en pseudo-langage, puis en Python, une fonction prenant 2 arguments de type entier et retournant le maximum des 2. NB : Comme le montre l’exercice précédent, il existe une fonction max en Python. Vous devez donc, dans cet exercice, écrire une fonction similaire portant un autre nom que la fonction Python existante. Correction FONCTION maximum(n1 EST_DU_TYPE NOMBRE, n2 EST_DU_TYPE NOMBRE) EST_DE_TYPE NOMBRE DEBUT_FONCTION IF (n1>n2) DEBUT_ALORS RENVOYER n1 FIN_ALORS SINON DEBUT_ALORS RENVOYER n2 FIN_ALORS FIN_FONCTION 4. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine 24 Fonctions def maximum(a,b): if(a>b): return a else: return b Exercice 3 Écrire en Python une fonction qui prend en argument la date du jour (dans 3 variables jourSysteme, moisSysteme, annéeSysteme), une date de naissance (dans 3 variables jourNais, moisNais, annéeNais) et calcule et renvoie l’âge d’une personne. L’âge d’une personne se calcule par la formule : (jourSysteme - jourNais + (moisSysteme - moisNais) * 365.25/12 + (anneeSysteme - annNais) *365.25) / 365.25). Vous pouvez importer le module time 5 pour obtenir la date système. Correction def age(jourSysteme,moisSysteme,anneeSysteme,jourNais, moisNais,annNais): return round((jourSysteme - jourNais + (moisSysteme - moisNais) * 365.25/12 + (anneeSysteme - annNais) *365.25) / 365.25) jourS=int(input("Quel jour somme-nous aujourd’hui (ex. 27) :")) moisS=int(input("Quel mois somme-nous aujourd’hui (ex. 6) :")) anneeS=int(input("En quelle année somme-nous aujourd’hui (ex. 2016) :")) jourN=int(input("Quel est le jour de votre date de naissance (ex. 19) :")) moisN=int(input("Quel est le mois de votre date de naissance (ex. 6) :")) anneeN=int(input("En quelle année ête-vous né(e) (ex. 1999) :")) print("Vous avez/allez avoir :", age(jourS,moisS,anneeS, jourN,moisN,anneeN), "ans") ou avec le module time : def ageAvecTime(jourNais,moisNais,annNais): return round((time.localtime (time.time()).tm_mday - jourNais + (time.localtime (time.time()).tm_mon - moisNais) * 365.25/12 + (time.localtime (time.time()).tm_year - annNais) * 365.25) / 365.25) 5. cf. https://docs.python.org/3/library/time.html Fonctions 25 jourN=int(input("Quel est le jour de votre date de naissance (ex. 19) :")) moisN=int(input("Quel est le mois de votre date de naissance (ex. 6) :")) anneeN=int(input("En quelle année ête-vous né(e) (ex. 1999) :")) print("Vous avez/allez avoir :", ageAvecTime(jourN,moisN,anneeN), "ans") Exercice 4 Écrire en pseudo-langage puis en Python : a) une fonction qui calcule le cube d’un entier n passé en paramètre ; b) une fonction qui calcule le volume d’une sphère de rayon r passé en paramètre en appelant la fonction cube() précédente. Pour rappel : le volume d’une sphère se calcule par la formule : (4/3) ∗ π ∗ r3 Correction FONCTION cube(n EST_DU_TYPE NOMBRE) // Fonction sans variable locale EST_DE_TYPE NOMBRE DEBUT_FONCTION RENVOYER n^3 FIN_FONCTION FONCTION volumeSphere(r EST_DU_TYPE NOMBRE) EST_DE_TYPE NOMBRE DEBUT_FONCTION //Avec appel de la fonction cube RENVOYER 4 * 3.1416 * cube(r)/3 FIN_FONCTION Dans l’exemple précédent, la fonction volumeSphere appelle la fonction cube en lui passant en paramètre la valeur de r (la valeur de r est copiée dans la valeur de l’argument n de la fonction cube). from math import * def cube(n): return n**3 def volumeSphere(r): return (4/3) * pi * cube(r) r=int(input(’Saisir un rayon :’)) print("Le volume de la sphere vaut :", volumeSphere(r)) 26 Fonctions Exercice 5 Écrire en Python une fonction permettant d’afficher une table de multiplication avec 3 arguments : base, debut et fin, la fonction affichant le résultat de la multiplication de base par tous les entiers situés entre debut et fin. Par exemple l’appel de tableMulti(8, 13, 17) devra afficher : Fragment 13 x 8 = 14 x 8 = 15 x 8 = 16 x 8 = 17 x 8 = de la table de multiplication par 8 : 104 112 120 128 136 Correction def tableMulti(base,debut,fin): print("Fragment de la table de multiplication par", base, ":") n=debut while(n<=fin): print(n, "x", base, "=", n * base) n=n+1 tableMulti(8, 13, 17) Exercice 6 Écrire 3 fonctions qui permettent de calculer le Plus Grand Commun Diviseur (PGCD) de deux nombres a et b (avec a ≥ b). 1. La première fonction pgcdParDiviseurs(a,b), avec a ≥ b, calculera les diviseurs de chacune des variables et affichera le plus grand diviseur commun. Par exemple, si on appelle pgcdParDiviseurs(63,42), les diviseurs de 63 étant 1;3;7;9;21;63 et ceux de 42 étant 1;2;3;6;7;14;21;42, on doit obtenir : Le plus grand diviseur commun de 63 et 42 est: 21 2. La deuxième fonction pgcdParDifferences(a,b), avec a ≥ b, utilisera l’algorithme des différences. Si un nombre est un diviseur de 2 nombres a et b, alors il est aussi un diviseur de leur différence a − b. Par exemple, si calcule le PGCD de 60 et 36. 60 - 36 = 24, donc le PGCD de 60 et 36 est un diviseur de 24. On effectue une nouvelle soustraction entre le résultat obtenu à la soustraction précédente et le plus petit des 2 termes de la soustraction précédente : 36 - 24 = 12. Par conséquent, le PGCD de 60 et 36 est un diviseur de 12. On arrête l’algorithme dès que la soustraction donne un résultat nul. Le PGCD correspond au résultat juste au dessus du zéro. Par conséquent, si on appelle pgcdParDifferences(60,36), on doit obtenir : Fonctions 60 36 24 12 27 - 36 24 12 12 = = = = 24 12 12 0 Le plus grand diviseur commun de 60 et 36 est: 12 3. La troisième fonction pgcdParEuclide(a,b), avec a ≥ b, utilisera l’algorithme d’Euclide. L’algorithme d’Euclide pour calculer le Plus Grand Commun Diviseur (PGCD) de deux entiers a et b (avec a ≥ b) consiste à effectuer une suite de divisions euclidiennes : — étape 1 : effectuer la division euclidienne de a par b ; on obtient r le reste ; si r est égal à 0, alors fin et le PGCD est égal à b, sinon aller à l’étape 2, — étape 2 : a reçoit alors la valeur de b et b reçoit la valeur de r et aller à l’étape 1. Cette méthode est plus rapide en général. Par exemple, si on appelle pgcdParEuclide(561,357), on doit obtenir : 561 divisé par 357 donne 1 en quotient et 204 en reste donc 561 = 357 x 1 + 204 357 divisé par 204 donne 1 en quotient et 153 en reste donc 357 = 204x1 + 153 204 divisé par 153 donne 1 en quotient et 51 en reste donc 204 = 153x1 + 51 153 divisé par 51 donne 1 en quotient et 0 en reste donc 153 = 51x3+ 0 Le plus grand diviseur commun de 561 et 357 est: 51 Correction FONCTION pgcdParDiviseurs(a EST_DE_TYPE NOMBRE, b EST_DE_TYPE NOMBRE) EST_DE_TYPE NOMBRE VARIABLES LOCALES pgcd EST_DE_TYPE NOMBRE cpt EST_DE_TYPE NOMBRE DEBUT_FONCTION pgcd <- 1 POUR cpt ALLANT de 0 A b DEBUT_POUR SI (((a % cpt)==0) ET ((b % cpt)==0) ET (cpt>pgcd)) DEBUT_ALORS pgcd <- cpt FIN_ALORS FIN_POUR RETOURNER pgcd FIN_FONCTION FONCTION maximum(n1 EST_DU_TYPE NOMBRE, n2 EST_DU_TYPE NOMBRE) EST_DE_TYPE NOMBRE 28 Fonctions DEBUT_FONCTION IF (n1>n2) DEBUT_ALORS RENVOYER n1 FIN_ALORS SINON DEBUT_ALORS RENVOYER n2 FIN_ALORS FIN_FONCTION FONCTION minimum(n1 EST_DU_TYPE NOMBRE, n2 EST_DU_TYPE NOMBRE) EST_DE_TYPE NOMBRE DEBUT_FONCTION IF (n1<n2) DEBUT_ALORS RENVOYER n1 FIN_ALORS SINON DEBUT_ALORS RENVOYER n2 FIN_ALORS FIN_FONCTION FONCTION pgcdParDifferences(a EST_DE_TYPE NOMBRE) EST_DE_TYPE NOMBRE VARIABLES LOCALES diff EST_DE_TYPE NOMBRE DEBUT_FONCTION diff <- a-b TANT_QUE (diff>0) DEBUT_TANT_QUE a <- maximum(diff,b) b <- minimum(diff,b) diff <- a-b FIN_TANT_QUE RETOURNER a FIN_FONCTION FONCTION pgcdParEuclide(a EST_DE_TYPE NOMBRE) EST_DE_TYPE NOMBRE VARIABLES LOCALES reste EST_DE_TYPE NOMBRE DEBUT_FONCTION reste <- a%b TANT_QUE (reste!=0) DEBUT_TANT_QUE a <- b Fonctions b <- reste reste <- a%b FIN_TANT_QUE RETOURNER b FIN_FONCTION DEBUT_ALGORITHME pgcdParDiviseurs(26,15) pgcdParDifferences(56,20) pgcdParEuclide(758,306) FIN_ALGORITHME 29 30 Listes en Python PSL Informatique CPES 1re année 2016-2017 Listes en Python Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 6 Exercice 1 : à la découverte des listes Exécuter dans l’interpréteur les instructions suivantes et analyser le résultat : L = [1,2,3,’toto’,8,True] L[0] L[4] len(L) L[len(L)] L[-1] L[1:-2] L[1:5:2] L[:5:-1] L.append(3) L.append([3]) L += 4 L += [4] L.count(’toto’) L.count(3) L.index(’toto’) L.index(3) ’toto’ in L [1,2,3] in L [1,3,2] in L list(range(10)) list(range(1,11)) list(range(1,11,2)) L = list(range(101,1,-1)) sum(range[1,6]) Remarque : En tapant help(list) dans l’interpréteur Python, on obtient toutes les fonctions sur les listes. Exercice 2 : Considérer le programme Python suivant : 6. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine Listes en Python 31 def f(k,taille,Liste): for j in range(k+1,taille): if Liste[k]>Liste[j]: x=Liste[k] Liste[k]=Liste[j] Liste[j]=x L=[] n=int(input()) for i in range(n): L.append(int(input())) for i in range(n-1): f(i,n,L) print(L) Sans exécuter le programme répondez aux questions suivantes : 1. Dans la fonction f, à quoi sert la variable x ? Quels sont les types des arguments de f ? 2. Décrire ce que réalise la fonction f. 3. Que permet de faire le bloc d’instructions suivant : for i in range(n): L.append(int(input())) 4. Que permet de faire le bloc d’instructions suivant : for i in range(n-1): f(i,n,L) Pourquoi la dernière valeur à considérer pour i dans cette boucle doit-elle être n-2 ? 5. Que va afficher le programme si l’utilisateur saisit d’abord 6 puis 14 3 54 2 1 5 ? Correction 1. A échanger les éléments d’indice k et l dans la liste L. Les arguments de la fonctionf() sont un entier k, indice dans une liste, une taille de liste et une liste (d’entiers). 2. La fonction positionne à la position d’indice k le plus petit entier situé entre les positions k+1 et taille-1. 3. Il permet de saisir n entiers dans la liste. 4. Il permet de trier la liste petit à petit en mettant le plus petit entier (parmi ceux situés entre les positions 0 et (taille-1)) à la position 0, puis le plus petit entier (parmi ceux situés entre les positions 1 et (taille-1)) à la position 1, etc. La boucle s’arrête à n-2, car le dernier échange positionne correctement les entiers situés entre les positions (taille-2) et (taille-1). 5. [1 2 3 5 14 54] Si le print(L) avait été mis dans le for, on aurait eu : [1, 14, 54, 3, 2, 5] [1, 2, 54, 14, 3, 5] [1, 2, 3, 54, 14, 5] 32 Listes en Python [1, 2, 3, 5, 54, 14] [1, 2, 3, 5, 14, 54] Exercice 3 1. Dans le module random se trouve une fonction nommée randint. Utilisez-la pour écrire une fonction, appelée listeAlea, qui renvoie une liste de 100 entiers tirés au hasard entre 0 et 99. 2. Ecrire une fonction, appelée absent, qui prend en argument une liste l crée avec la fonction listeAlea et, renvoie le nombre d’entiers compris entre 0 et 99 qui n’appartiennent pas à l. 3. Dans le programme principal, recommencer ce tirage aléatoire 1000 fois et calculer, et afficher, la moyenne du nombre d’absents. 4. Comparer à la valeur théorique. import random def listeAlea(): L=[] for i in range(100): L.append(random.randint(0,99)) return L def nbreAbsent(L): nb=0 for i in range(100): if not(i in L): nb+=1 return nb moyenne=0 for essai in range(1000): l=listeAlea() moyenne+=nbreAbsent(l) print(moyenne/1000) Nbre moyen = 36.444 Nbre théorique = proba d’être absent pA = 0.3660323412732292 => 100*pA=36.60323412732292 Exercice 4 1. Écrire une fonction qui prend trois arguments n, m et p et qui affiche les m premiers multiples de n de la façon suivante : les multiples sont séparés par des ; et on passera à la ligne tous les p multiples. Listes en Python 33 2. Dans le programme principal, appeler cette fonction pour afficher les 20 premiers multiples de 7 en passant à la ligne tous les 3 multiples. Exemple d’exécution : Combien de multiples de 7 voulez-vous afficher ? 20 Vous irez à la ligne après ... (nombre strictement positif svp) : 3 7;14;21 28;35;42 49;56;63 70;77;84 91;98;105 112;119;126 133;140; Exercice 5 : somme de deux listes Soit deux listes d’entiers L1 et L2. Ecrire une fonction qui prend L1 et L2 en arguments et renvoie la liste LRES qui contient la somme des éléments de même rang de la liste L1 et de la liste L2 auxquels on ajoute les derniers éléments de la liste la plus longue. Appeler votre fonction pour afficher la somme de [1,2,3,4,5] et [2,15,18] qui devrait donner [3,17,21,4,5]. Correction l1=[1, 2, 3,4,5] l2=[2,15,18] lres=list() i=0 while i<len(l1) and i<len(l2): lres.append(l1[i]+l2[i]) i+=1 if i==len(l1): lres.extend(l2[i:]) else: lres.extend(l1[i:]) print(lres) Exercice 6 : une suite Soit la suite U définie comme suit : Un = 5Un−1 + 10Un−2 avec U0 = 1 et U1 = 2. Écrire la fonction, appelée suiteU, qui prend en argument n et qui renvoie la liste [U0 , U1 , ..., Un−1 , Un ]. Ecrire votre programme principal qui lit n ≥ 2 saisi par l’utilisateur et appelle la fonction suiteU pour afficher les n premiers termes de la suite U . 34 Listes en Python Correction n=int(input()) serie=[1,2] for i in range(2,n+1): serie.append(5*serie[i-1]+10*serie[i-2]) print(serie) Exercice 7 : suppression dans une liste Étant donnés une liste L et un élément x, écrire une fonction qui permet de supprimer toutes les occurences de l’élément x dans la liste L. Tester votre fonction pour l’élément 0 dans la liste L = [0, 1, 2, 0, 0, 4]. Correction #Première correction L=[0,1,2,0,0,4] x=int(input("Quelle est la valeur à supprimer ? ")) i=0 while i<len(L): if L[i]==x: L.pop(i) else : i=i+1 print("verif", L) Attention : bien expliquer que l’on ne peut pas utiliser une boucle for ici car len(L) est évalué uniquement au premier passage de la boucle, par la suite si la liste L est modifiée, alors len(L) n’est pas mis à jour. #Seconde correction L=[0,1,2,0,0,4] x=int(input("Quelle est la valeur à supprimer ? ")) while x in L: L.remove(x) print("verif", L) Exercice 8 Écrire une fonction en Python qui saisit une liste de listes de nombres. Puis, écrire une fonction qui prend en argument une liste de listes et retourne la somme de la liste de nombres la plus longue (s’il y en a plusieurs, on prendra la première). Par exemple, pour la liste [[1, 2, 3], [], [2, 3, 0, 4], [2, 5], [6, 0, 2, 4]], le programme affichera 9. Correction L=[[1,2,3],[],[2,3,0,4],[2,5],[6,0,2,4]] longueur=0 total=0 Listes en Python 35 for j in range(len(L)): taille=len(L[j]) if taille>longueur: somme=0 for i in range(taille): somme+=L[j][i] longueur=taille total=somme print("la liste ", L[j], "contient ",taille, " éléments dont la somme est ", somme) print("la plus longue liste contient ", longueur, " éléments dont la somme est ", total) Exercice 9 : gestion des notes Après un examen, les notes des étudiants sont les suivantes : Florian : 2, Antoine : 12, Charles1 : 15, Robert : 0, Charles2 : 8, Erwan : 7, Jean : 20, Xavier : 11, Didier : 20, Alain : 0, Hadi : 12. 1. Utiliser des listes pour stocker les noms des étudiants et les notes associées. 2. Ecrire une fonction qui prend en argument la liste de note et qui calcule et retourne la moyenne de l’examen. 3. Ecrire une fonction qui prend en argument la liste de noms et la liste de notes et retourne la liste des mentions : « admis » si la note est supérieure ou égale a 10, ou bien « recalé » sinon. 4. Ecrire une fonction qui prend en argument la liste de noms et la liste des mentions et renvoie la liste des étudiants ayant réussi leur examen. 5. Dans votre programme principal, appeler ces fonctions pour : afficher la moyenne et afficher la liste des étudiants ayant réussi leur examn. Correction Noms=["Florian","Antoine","Charles1","Robert","Charles2", "Erwan","Jean", "Xavier","Didier","Alain","Hadi"] Notes=[2,12,15,0,8,7,20,11,20,0,12] total=len(Noms) print(Noms) print(Notes) moyenne=0 for i in Notes: moyenne+=i moyenne=moyenne/len(Notes) print("la moyenne est ", moyenne) admis=[] recale=[] for i in range(total): if Notes[i]>=10: print(Noms[i], "est admis avec ", Notes[i]) 36 Listes en Python admis.append(Noms[i]) else: print(Noms[i], "est recalé avec ", Notes[i]) if Notes[i]!=0: recale.append(Noms[i]) print("les étudiants recalés sont finalement : ", recale) total = int(input("Combien d’étudiants et de notes à saisir en plus?")) for i in range(total): nom=input("Quel est le nom de l’étudiant?") note=int(input("Quelle est sa note?")) Noms.append(nom) Notes.append(note) Fonctions - Récursion 37 CPES 1re année 2016-2017 PSL Informatique Fonctions - Récursion 7 Exercice 1 Que font ces deux programmes et qu’affichent-ils ? # Programme 1 def f(n): global c, p c = n+1 return p*2 # Programme 2 def f(n): global c, p c = n+1 p = p*2 return p c = 0 p = 1 c = 0 p = 1 for i in range(10): n = f(i) print(c, n) for i in range(10): n = f(i) print(c, n) Correction Les deux programmes effectuent dix fois une boucle et affiche la valeur de c puis la valeur de retour de la fonction f(). La variable globale c est modifiée dans la fonction et prend simplement la valeur du paramètre +1 : comme le paramètre est égal à l’indice de boucle (de 0 à 9), la variable c va aller de 1 à 10. On a donc dix lignes d’affichées, commençant par les nombres de 1 à 10. La fonction f() du programme 1 renvoie la valeur de p*2 mais comme la variable globale p n’est jamais modifiée, cette valeur vaut toujours 1 ∗ 2 = 2 ; c’est donc ce nombre qui s’affiche sur les dix lignes. Au contraire, dans le second programme, la variable globale p est modifiée et multipliée par 2 à chaque passage dans la fonction avant d’être renvoyée. Elle prend donc les valeurs successives 2, 4, 8... et c’est aussi ce qui est affiché : les nombres de 1 à 10 suivis des puissances de 2 de 21 à 210 . Exercice 2 Que font ces deux programmes et qu’affichent-ils ? 7. Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 38 Fonctions - Récursion # Programme 1 def gp(): global p return p # Programme 2 def gp(): global p return p def f(n): global c c = n+1 p = gp()*2 return p def f(n): global c, p c = n+1 p = gp()*2 return p c = 0 p = 1 c = 0 p = 1 for i in range(10): n = f(i) print(c, n) for i in range(10): n = f(i) print(c, n) Correction L’affichage est exactement le même que dans l’exercice précédent. Le programme 2 fonctionne de la même manière : la fonction gp() renvoie la valeur de p qui est ensuite multipliée par 2 dans f() et remise dans la variable globale p : celle-ci croit donc comme les puissances de 2. Le programme 1 semble identique, à l’exception de la variable p qui n’est plus globale dans la fonction f() ! C’est donc une variable locale qui prend simplement la valeur de la variable globale p (renvoyée par gp() et toujours égale à 1 car jamais modifiée) multipliée par 2. Exercice 3 1. Écrire une fonction récursive, appelée sommeRec(), qui prend comme argument une valeur entière n, et qui calcule la somme des n premiers entiers. Appeler cette fonction pour qu’elle calcule la somme des entiers allant de 0 à 100. 2. Transformer la fonction sommeRec() afin qu’elle admette 2 arguments debut et fin, et qu’elle calcule la somme des entiers variant de la valeur entière debut à la valeur entière fin. Appeler cette fonction pour calculer la somme des entiers variant de 50 à 100. Correction 1. def sommeRec(n): if (n > 1): return n + sommeRec(n - 1) else: return 1 Appel : x = sommeRec(100). Fonctions - Récursion 39 2. def sommeRec(debut, fin): if (fin >= debut): return fin + sommeRec(debut, fin - 1) else: return 0 ou def sommeRec(debut, fin): if (fin >= debut): return debut + sommeRec(debut + 1, fin) else return 0 Appel : x = sommeRec(50,100)... Exercice 4 Les n premiers nombres de Fibonacci sont définis par : F ib(0) = F ib(1) = 1, F ib(i) = F ib(i − 1) + F ib(i − 2) si i ≥ 2 1. Programmer la fonction itérative FibIt() calculant les n premiers nombres de Fibonacci. 2. Programmer la fonction récursive FibRec() calculant les n premiers nombres de Fibonacci. 3. A l’aide de la bibliothèque time et de la fonction clock(), comparer les temps de calcul de FibIt(n) et FibRec(n) pour n=35 puis n=70. Que constatez-vous ? 4. Écrire et programmer une version récursive Fib2Rec() ne faisant que n appels récursifs seulement. Toujours à l’aide de la fonction clock(), mesurer le temps de calcul de Fib2Rec(n) pour n=35 puis n=70. Que constatez-vous ? Correction def fibo(n): if (n<2): return 1 else: i=2 f0=1 f1=1 while(i<=n): tmp = f0 + f1 f0 = f1 f1 = tmp i+=1 return f1 def fiboRec(n): 40 Fonctions - Récursion if(n<2): return 1 else : return (fiboRec(n-1)+ fiboRec(n-2)) def fiboRec2(n,a,b): if(n<2): return a else : return fiboRec2(n-1,b+a,a) tps=time.clock() resul=fibo(35) print(resul, time.clock()-tps) tps=time.clock() resul=fiboRec(35) print(resul, time.clock()-tps) tps=time.clock() resul=fiboRec2(35,1,1) print(resul,time.clock()-tps) Exercice 5 Écrire une fonction récursive calcDiff() qui prend en argument une liste d’entiers t et qui calcule et affiche un entier de la façon suivante : à partir de t, on calcule la liste des différences de 2 éléments consécutifs de t (à savoir t[i+1]-t[i]), et on recommence sur cette liste des différences (comportant un élément en moins que t) jusqu’à obtenir une liste d’un seul élément. Par exemple, partant de la liste [3,5,10], la fonction doit afficher 3 (en passant par le calcul de la liste intermédiaire [2,5]). Correction def calculDiff(t): if len(t)>1: diff=[] for i in range(0,len(t)-1): diff.append(t[i+1]-t[i]) return calculDiff(diff) else: return t[0] print(calculDiff([3,5,10])) Exercice 6 1. Écrire une fonction prenant un entier a et un entier positif n et qui retourne an de manière itérative. 2. Écrire une fonction récursive calculant cette même puissance. Fonctions - Récursion 41 3. Sachant que a0 = 1 et n a = (a(n/2) )2 si n est pair (n−1)/2) 2 a × (a ) si n est impair écrire une deuxième fonction récursive plus maline calculant cette même puissance. 4. Afficher les puissances de 2 de 20 à 230 en appelant les deux fonctions récursives cidessus. On affichera également pour chaque puissance le nombre d’appels à chaque fonction, comptabilisés à l’aide d’une variable globale. Correction def puissance(a, n): global appels appels += 1 if (n==0): return 1 else: return a*puissance(a, n-1) def puissance2(a, n): global appels appels += 1 if (n==0): return 1 elif (n%2==0): #n pair i = puissance2(a, n/2) return i*i else: #n impair i = puissance2(a, (n-1)/2) return a*i*i for p in range(31): appels = 0 print("2 puissance", p, "=", puissance(2, p), "(en", appels, "appels)") appels = 0 print("2 puissance2", p, "=", puissance2(2, p), "(en", appels, "appels)") 42 Algorithmes de recherche CPES 1re année 2016-2017 PSL Informatique Algorithmes de recherche Exercice 1 : Recherche séquentielle dans un tableau Soit T un tableau de n éléments de type NOMBRE (dont certains sont éventuellement identiques) et soit v une valeur de type NOMBRE. 1. Ecrire un algorithme qui renvoie le plus petit indice i tel que T[i] soit égal à v ou -1 s’il n’en existe pas (le tableau est parcouru par indice croissant). 2. Donner la complexité de cet algorithme en fonction de n. 3. Traduire en Python l’algorithme proposé question 1. 4. Ecrire un algorithme qui renvoie le plus grand indice i tel que T[i] soit égal à v ou -1 s’il n’en existe pas (le tableau est parcouru par indice croissant). 5. Donner la complexité de ce programme en fonction de n. 6. Quel est l’inconvénient de ce programme par rapport au précédent ? 7. En Python, la boucle while permet de réaliser des boucles dont l’indice est décroissant. Utiliser ce type de boucle pour proposer un programme plus efficace pour trouver le plus grand indice. Exercice 2 : Recherche dichotomique dans un tableau trié On suppose maintenant que le tableau T est trié. Pour trouver un indice de v dans T (retourne -1 si v n’est pas un élément de T), on peut alors appliquer l’approche dichotomique suivante : calculer l’indice du milieu = d(n − 1)/2e et comparer v avec T[milieu]. s’il y a égalité, renvoyer milieu. sinon si v < T[milieu] et milieu > 0, rechercher v dans le sous-tableau indicé de 0 à milieu-1. Sinon si v > T[milieu] et milieu < n-1, rechercher v dans le soustableau indicé de milieu+1 à n-1. 1. 2. 3. 4. Ecrire cet algorithme en pseudo-code (sans utiliser la récursivité). Donner sa complexité. Modifier cet algorithme pour qu’il renvoie le plus petit indice. Modifier cet algorithme pour qu’il renvoie le plus grand indice. Modifier cet algorithme pour qu’il renvoie le nombre d’indices i tels que T[i] soit égal à v. 5. Programmer en python l’algorithme de la question 2. 6. Ecrire une version récursive de cette recherche dichotomique dans un tableau trié. 7. Générer aléatoirement dix tableaux de taille 1000 jusqu’à 1000000 par pas de 100000 et, pour chaque taille de tableaux comparer les temps de calcul moyens de vos programmes de recherche séquentielle d’une part, et de recherche dichotomique d’autre part. Que constatez-vous ? Algorithme de recherche 43 Algorithme en pseudo-code : VARIABLE T EST_DE_TYPE tableau de n NOMBRE deb, fin, v EST_DE_TYPE NOMBRE DEBUT_ALGO deb=0 fin=n TANT_QUE deb<fin FAIRE m=floor((deb+fin)/2) SI T[m]==v ALORS renvoyer m SINON DEBUT_SINON SI v<T[m] ALORS fin=m SINON deb=m+1 FIN_SINON FIN_TANT_QUE renvoyer -1 FIN_ALGO Complexité : soit k le nombre d’itérations de la boucle tant que. Dans le pire de cas v n’appartient pas au tableau et on va rechercher dans un tableau de taille n/2 jusqu’a ce qu’il ne reste plus que 1 éléments : (((n/2)/2)/2.... = 1 n/2k = 1 n = 2k log2 n = k import math import random import time def recherche(T,v): deb=0 fin=len(T) while deb<fin: if T[deb]==v: return deb deb+=1 return -1 def rechercheDichoIt(T,v): deb=0 fin=len(T) while deb<fin: m=math.floor((fin+deb)/2) if T[m]==v: i=m 44 Algorithmes de recherche while T[i-1]==v: i-=1 return i else: if v<T[m]: fin=m-1 else : deb=m+1 return -1 def rechercheDichoRec(T,deb,fin,v): if deb==fin: return -1 else: m=math.floor((fin+deb)/2) if T[m]==v: i=m while T[i-1]==v: i-=1 return i else: if v<T[m]: return rechercheDichoRec(T,deb,m,v) else : return rechercheDichoRec(T,m+1,fin,v) Résultats : >>> (executing lines 1 to 69 of "algoRecherche.py") Taille = 1000 Seq = 0.05 DichIt = 0.01 DichRec = 0.01 Index = 0.01 Taille = 101000 Seq = 4.14 DichIt = 0.06 DichRec = 0.06 Index = 0.57 Taille = 201000 Seq = 8.49 DichIt = 0.13 DichRec = 0.12 Index = 1.19 Taille = 301000 Seq = 16.00 DichIt = 0.20 DichRec = 0.19 Index = 2.18 Taille = 401000 Seq = 23.99 DichIt = 0.27 DichRec = 0.26 Index = 3.24 Taille = 501000 Seq = 31.71 DichIt = 0.27 DichRec = 0.28 Index = 4.35 Taille = 601000 Seq = 20.12 DichIt = 0.44 DichRec = 0.43 Index = 3.01 Taille = 701000 Seq = 31.35 DichIt = 0.45 DichRec = 0.45 Index = 4.28 Taille = 801000 Seq = 40.95 DichIt = 0.48 DichRec = 0.48 Index = 5.64 Taille = 901000 Seq = 62.57 DichIt = 0.53 DichRec = 0.57 Index = 8.54 Taille = 1001000 Seq = 77.49 DichIt = 0.75 DichRec = 0.75 Index = 10.39 Représentation des nombres 45 CPES 1re année 2016-2017 PSL Informatique Représentation des nombres Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 8 Exercice 1 1. Quelle est l’écriture décimale du nombre qui s’écrit 11001 en binaire ? Quelle est l’écriture binaire du nombre décimal 555 ? 2. Quelle est l’écriture décimale du nombre qui s’écrit 11001000 en binaire dans la représentation en complément à 2 ? Quelle est l’écriture binaire du nombre décimal -555 dans la représentation en complément à 2 sur 12 bits ? 3. On considère les deux nombres binaires 11001000 et 01001000 écrits dans la représentation en complément à 2. Calculer (en binaire) la somme de ces deux nombres et vérifier que le résultat binaire obtenu correspond à la somme des deux valeurs décimales correspondant aux deux nombres binaires. Correction 1. 110112 = 2510 ; 55510 = 1000101011 2. 11001000 est négatif. Son complément à 2 vaut 00111000 soit 56. Donc 110010002 = −5610 en représentation complément à 2. On sait que 55510 = 001000101011 (bien prendre les 12 bits), donc on prend le complément à un qui vaut 110111010100 et on ajoute 1 ce qui donne 1101110101012 = −55510 3. On a bien 1 + 1 11 1 0 1 0 0 0 0 0 01 1 0 1 1 0 0 0 0 0 0 0 0 0 0 Et on vérifier bien que −56 + 72 = 16 Exercice 2 1. Donner sur 8 bits les représentations complément à 2 des nombres décimaux 45, 73, 84, –99, –102 et –118. 2. Effectuer la soustraction 122−43 dans la représentation en complément à 2 en n’utilisant que l’addition. 8. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine 46 Représentation des nombres Correction S et V 45 0010 1101 73 0100 1001 1. 84 0101 0100 -99 1110 0011 -102 1110 0110 -118 1111 0110 Comp. à 1 0010 1101 01001 001 0101 0100 1001 1100 1001 1001 1000 1001 Comp. à 2 0010 1101 0100 1001 0101 0100 1001 1101 1001 1010 1000 1010 2. 122 − 43 = 122 + (−43) 122 : −43 : 79 : 01111010 11010101 01001111 Exercice 3 Écrire un algorithme qui attend une valeur décimale (qu’on supposera positive ou nulle) et affiche son écriture binaire. Pour ce faire, on utilisera un algorithme itératif qui effectue en boucle les divisions successives par 2 et construit une chaîne portant le résultat à afficher à la fin. Implémenter votre algorithme en Python. Proposer également une version récursive de votre algorithme. Correction Attention, il faut penser au cas particulier 0. VARIABLES N, TMP EST_DU_TYPE NOMBRE S EST_DU_TYPE CHAINE_CARACTERES DEBUT_ALGORITHME ECRIRE "Valeur décimale ?" LIRE N SI (N == 0) ALORS DEBUT_ALORS S <- "0" FIN_ALORS SINON DEBUT_SINON S <- "" TMP <- N TANT_QUE (TMP>0) FAIRE DEBUT_TANT_QUE S <- TMP%2 + S TMP <- TMP//2 FIN_TANT_QUE FIN_SINON ECRIRE N, " s’écrit ", S, " en binaire" Représentation des nombres 47 FIN_ALGORITHME La version itérative : TMP = N = int(input("Entrez une valeur decimale : ")) if N == 0: s = "0" else: s = "" while (TMP>0) : s = str(TMP%2) + s TMP //= 2 print(N, "s’ecrit", s, "en binaire.") Et la version récursive : def f(N): if (N==0): print("0") elif (N==1): print("1", end="") else: f(N//2) print(N%2, end="") N = int(input("Entrez une valeur decimale : ")) f(N) Exercice 4 Écrire un algorithme qui attend une chaîne uniquement composée de symboles binaires (c’està-dire de ’0’ et de ’1’) et affiche la valeur décimale correspondante en supposant que la chaîne représente un nombre positif ou nul. Correction VARIABLES N EST_DU_TYPE NOMBRE S EST_DU_TYPE CHAINE_CARACTERES DEBUT_ALGORITHME ECRIRE "CHAINE BINAIRE ?" LIRE S N <- 0 POUR i ALLANT_DE 0 A LONGUEUR(S)-1 DEBUT_POUR N <- N*2 SI (S[i] == "1") FAIRE 48 Représentation des nombres DEBUT_ALORS N <- N + 1 FIN_ALORS FIN_POUR ECRIRE "Valeur décimale : ", N FIN_ALGORITHME Traduire votre algorithme en Python. Correction s = input("Chaine binaire ?") N = 0 for bit in s: N *= 2 if bit == "1": N += 1 print ("Valeur decimale : ", N) Exercice 5 On considère la suite numérique : 9 3 3 Un+1 = − Un2 + Un − 8 4 8 1. Montrer que si U0 = 3 ou si U0 = 13 , la suite est constante. 2. Ecrire une fonction en Python qui prend U0 en argument, et qui calcule et affiche les 70 premiers termes de la suite. 3. Appeler cette fonction avec comme argument 3, puis comme argument 1/3 ; comment interprétez-vous les résultats ? Correction 1. On calcule simplement U1 et, dans les deux cas, on aboutit à U1 = U0 . La suite est donc constante. 2. def itere(U0): u = U0 for i in range(70): print("U", i, " = ", u, sep="") u = -3.0*u*u/8.0 + 9.0*u/4.0 - 3.0/8.0 print("Calcul pour U0 = 3") itere(3.0) print("\nEt pour U0 = 1/3") itere(1.0/3.0) Le comportement est sans surprise pour U0 = 3, on obtient bien la valeur 3 pour les 70 premières itérations. En revanche, lorsque U0 = 13 , les premières valeurs tournent autour de 1/3 puis s’en éloignent et la valeur calculée finit par converger vers 3. Représentation des nombres 49 3. La suite est de la forme Un+1 = f (Un ) et, si elle converge, c’est vers un point fixe de f , c’est-à-dire une solution de l’équation f (X) = X. En résolvant cette équation du second degré, on trouve que f admet deux points fixes, 3 et 1/3. Le point fixe 3 est stable (la dérivée de f en 3 vaut 0), ce qui implique que le calcul est numériquement stable : si on itère f à partir d’une valeur proche de 3, les valeurs successivement obtenues se rapprochent du point fixe 3 ; c’est bien ce que l’on obtient avec le programme précédent. En revanche, le point fixe 1/3 est instable (la dérivée de f en 1/3 vaut 2). En d’autres termes, des itérations commencées à une valeur proche de 1/3 s’en éloignent. Dans le programme précédent, on démarre les itérations avec la valeur 1/3 ; on devrait donc rester sur le point fixe, mais 1/3 n’est pas exactement représentable en puissances négatives de 2. Par conséquent, le programme débute le calcul avec une valeur binaire très proche de 1/3 mais pas parfaitement égale à 1/3. Cela suffit pour faire diverger le calcul vers l’autre point fixe, 3. Exercice 6 On considère la fonction f (n) = 1 1+ 2 n n2 On peut écrire : n2 n2 !! 1 1 lim 1 + 2 = lim exp ln 1+ 2 ∞ ∞ n n 1 2 = lim exp n ln 1 + 2 ∞ n 1 ≈ lim exp(n2 × 2 ) ∞ n ≈ exp(1) = e Écrire une fonction Python qui calcule la valeur de f (n) pour un n donné en paramètre. (On rappelle que ** est l’opérateur puissance.) Écrire une boucle qui calcule et affiche f (n) pour n allant de 1 à 100 millions par pas de 200 000. Qu’observe-t-on ? Correction def f(n): return (1+1/(n*n))**(n*n) for i in range(1,100000000, 200000): print(f(i)) Le calcul converge tout de suite vers e mais se met ensuite à osciller autour de cette valeur, avec une amplitude de plus en plus grande. Les valeurs croissent ensuite pour arriver un peu au-dessus de 7.35, puis le calcul donne systématiquement 1.0. Le souci intervient lorsque n est trop grand et que le calcul flottant de 1/n2 provoque des erreurs d’arrondi qui finissent par s’accumuler. La valeur finale s’explique par le fait que la mise à la puissance finale finit par dépasser la précision de la représentation. 50 Représentation des nombres Exercice 7 Les calculs sur des nombres entiers s’effectuent exactement (la taille de représentation n’est pas limitée) alors que les calculs sur des nombres réels sont approchés (un nombre réel se représente sur huit octets). En effectuant une boucle, écrire un programme Python qui compare la valeur exacte de 3i et la partie entière de 3.0i et indique à quel exposant elles diffèrent. Correction i=1 while 3**i == int(3.0**i): i+=1 print("Les deux valeurs diffèrent pour l’exposant", i, ":", 3**i, "et", int(3.0**i)) Fichiers 51 CPES 1re année 2016-2017 PSL Informatique Lire et écrire dans des fichiers Exercices préparées par V. Gabrel, E. Lazard, M. Manouvrier et C. Murat 9 Un fichier est une suite d’informations enregistrée de manière permanente sur le disque. Il peut contenir le code d’un programme (c’est-à-dire la suite d’instructions machine le composant) ; on parle alors de fichier exécutable. Il peut aussi contenir des données qui vont être lues par un programme. Il existe beaucoup de formats de fichiers différents. Dans un fichier de format texte, toutes les informations sont écrites sous la forme de caractères imprimables (c’est-à-dire lettres, chiffres, symboles de ponctuation...) séparés par des espaces, des tabulations et des caractères de fin de ligne. L’avantage de ces fichiers est qu’il est possible de les ouvrir dans n’importe quel logiciel (par exemple un éditeur de texte) : comme tous ces caractères sont imprimables, le texte du fichier est directement lisible à l’écran. Attention à ne pas confondre le format du fichier et l’utilisation qu’un logiciel en fait. Ainsi, un logiciel de traitement de texte, comme Microsoft Word, va afficher le contenu d’un de ses fichiers comme du texte à l’écran mais le fichier lui-même n’est pas au format texte. Il contient en fait de nombreuses informations supplémentaires utilisées par le logiciel : polices de caractères utilisées, taille, largeur de page, illustrations... Il n’est donc pas possible d’afficher directement le contenu brut du fichier à l’écran. Un fichier permet de garder des informations et données de manière permanente sur le disque. Un programme Python doit donc être capable d’y écrire des données, de les modifier et de les relire plus tard. L’utilisation d’un fichier se fait toujours de la même manière : 1. il faut tout d’abord « ouvrir » le fichier, c’est-à-dire le désigner par son nom afin que le système nous permette d’y avoir accès ; 2. on peut ensuite lire ou écrire dans le fichier ; éventuellement s’y déplacer pour récupérer une information particulière ; 3. enfin le fichier doit être « fermé », signalant ainsi au système que l’on a fini de l’utiliser et qu’il peut valider et reporter les éventuelles données modifiées sur le disque. Un fichier peut se trouver sur n’importe quel support de mémorisation : disque dur, clé USB, CD/DVD... On pourra toujours considérer le contenu d’un fichier comme une suite de caractères, ce qui signifie que vous pouvez traiter ce contenu, ou une partie quelconque de celui-ci, à l’aide des fonctions servant à traiter les chaînes de caractères. Où sont mes fichiers ? Il existe deux moyens de désigner un fichier par son nom : indiquer son « nom absolu » (c’est-à-dire la suite des répertoires formant le chemin depuis la racine de l’arborescence des fichiers jusqu’au fichier lui-même) ou son « chemin relatif » depuis le répertoire courant. 9. Cours également dispensé en 1ère année de licence Mathématique-Informatique-Économie (MIE) à l’Université Paris-Dauphine 52 Fichiers Lors du lancement de l’interpréteur, le répertoire courant est normalement initialisé à la racine du dossier personnel de l’utilisateur. Cela signifie que tout fichier uniquement désigné par son nom sera créé ou ouvert dans ce répertoire. Si l’on souhaite regrouper ses fichiers Python dans un sous-dossier, il est plus simple de désigner ce sous-dossier comme le répertoire courant. On peut le faire une bonne fois pour toute dans l’interpréteur de commandes à l’aide de la fonction chdir() (signifiant CHange DIRectory) du module os : >>> from os import chdir >>> chdir("nomNouveauRépertoireCourant") On peut indiquer le nouveau répertoire courant soit par son chemin absolu, soit par son chemin relatif à partir du répertoire courant précédent. Notons que la fonction getcwd() (GET Current Working Directory) du module os permet de connaître le répertoire courant. Une fois cette commande chdir() exécutée dans l’interpréteur, le répertoire courant est positionné à sa nouvelle valeur pour tous les prochains fichiers que l’on serait amené à exécuter. Il sera alors très facile de ne plus s’en occuper et, dans le code, de désigner les fichiers simplement par leur nom. Écriture dans un fichier Sous Python, l’accès aux fichiers est assuré par l’intermédiaire d’un objet-fichier que l’on crée à l’aide de la fonction open(). Après avoir appelé cette fonction, on peut lire et écrire dans le fichier en utilisant les fonctions spécifiques de cet objet-fichier. L’exemple ci-dessous montre comment ouvrir un fichier « en écriture », y enregistrer deux chaînes de caractères, puis le refermer. Notons bien que si le fichier n’existe pas encore, il sera créé automatiquement. Par contre, si le nom utilisé concerne un fichier préexistant qui contient déjà des données, les caractères qui y seront enregistrés viendront s’ajouter à la suite de ceux qui s’y trouvent déjà. >>> >>> >>> >>> f = open("test.txt", "a") f.write("Bonjour\n") f.write("Ceci est un test d’ecriture") f.close() — La première ligne crée l’objet-fichier f, lequel fait référence à un fichier véritable (sur le disque) dont le nom est "test.txt". La fonction open() attend deux arguments, qui doivent être des chaînes de caractères. Le premier argument est le nom du fichier à ouvrir, et le second est le mode d’ouverture. Ici, "a" indique qu’il faut ouvrir ce fichier en mode « ajout » (append), ce qui signifie que les données à enregistrer seront ajoutées à la fin du fichier, à la suite de celles qui s’y trouvent déjà. Nous aurions pu utiliser aussi le mode "w" (pour write) ; Python crée alors toujours un nouveau fichier (vide) et l’écriture des données commence à partir du début de ce nouveau fichier ; s’il existe déjà un fichier de même nom, celui-ci est préalablement effacé. — La fonction write() réalise l’écriture proprement dite. Les données à écrire doivent être fournies en argument. Ces données sont enregistrées dans le fichier les unes à la suite des autres (c’est la raison pour laquelle on parle de fichier à accès séquentiel). Chaque nouvel appel à write() continue l’écriture à la suite de ce qui est déjà enregistré. Fichiers 53 — La fonction close() referme le fichier. Celui-ci est désormais disponible pour tout usage. Lecture depuis un fichier Nous pouvons maintenant ouvrir de nouveau le fichier, mais cette fois « en lecture », de manière à pouvoir y relire les informations qui ont été enregistrées dans l’étape précédente : >>> inF = open("test.txt", "r") >>> s = inF.read() >>> print(s) Bonjour Ceci est un test d’ecriture >>> inF.close() La fonction read() lit les données présentes dans le fichier et les transfère dans une variable de type « chaîne » (string). Si on utilise cette fonction sans argument, la totalité du fichier est transférée. — Le fichier que nous voulons lire s’appelle "test.txt". L’instruction d’ouverture de fichier devra donc nécessairement faire référence à ce nom-là. Si le fichier n’existe pas, nous obtiendrons un message d’erreur. Par contre, nous ne sommes tenus à aucune obligation concernant le nom à choisir pour l’objet-fichier. C’est un nom de variable quelconque. Ainsi, dans notre première instruction, nous avons choisi de créer un objet-fichier inF, faisant référence au fichier réel "test.txt", lequel est ouvert en lecture (argument "r"). — read() lit l’intégralité du fichier et renvoie le résultat comme une chaîne. Ici, même si l’écriture s’est faite par deux write() successifs, l’ensemble du fichier, donc les deux chaînes (avec le \n intermédiaire), est récupéré par le read(). — La fonction read() peut également être utilisée avec un argument. Celui-ci indiquera combien de caractères doivent être lus, à partir de la position déjà atteinte dans le fichier : >>> inF = open(’test.txt’, ’r’) >>> s = inF.read(7) >>> print(s) Bonjour >>> s = inF.read(15) >>> print(s) Ceci est un te S’il ne reste pas assez de caractères au fichier pour satisfaire la demande, la lecture s’arrête tout simplement à la fin du fichier : >>> s = inF.read(100) >>> print(s) st d’ecriture Si la fin du fichier est déjà atteinte, read() renvoie une chaîne vide : 54 Fichiers >>> s = inF.read(100) >>> print(s) >>> inF.close() Travailler ligne par ligne avec les fichiers textes Un fichier texte est un fichier qui contient des caractères imprimables et des espaces organisés en lignes successives, ces lignes étant séparées les unes des autres par un caractère spécial appelé « marqueur de fin de ligne » 10 . Il est très facile de traiter ce genre de fichiers sous Python. Les instructions suivantes créent un fichier texte de quatre lignes : >>> >>> >>> >>> f = open("fichierTexte.txt", "w") f.write("Ceci est la ligne un\nVoici la ligne deux\n") f.write("Voici la ligne trois\nVoici la ligne quatre\n") f.close() Notons le marqueur de fin de ligne ’\n’ inséré dans les chaînes de caractères, aux endroits où l’on souhaite séparer les lignes de texte dans l’enregistrement. Sans ce marqueur, les caractères seraient enregistrés les uns à la suite des autres. Lors des opérations de lecture, les lignes d’un fichier texte peuvent être extraites séparément les unes des autres. La fonction readline(), par exemple, ne lit qu’une seule ligne à la fois (en incluant le caractère de fin de ligne) : >>> f = open("fichierTexte.txt","r") >>> t = f.readline() >>> print(t) Ceci est la ligne un >>> print(f.readline()) Voici la ligne deux La fonction readlines() transfère toutes les lignes restantes dans une liste de chaînes : >>> t = f.readlines() >>> print(t) [’Voici la ligne trois\n’, ’Voici la ligne quatre\n’] >>> f.close() — On peut bien évidemment parcourir la liste (à l’aide d’une boucle while/for par exemple) pour en extraire les chaînes individuelles. — La fonction readlines() permet de lire l’intégralité d’un fichier en une instruction seulement. Cela n’est possible toutefois que si le fichier à lire n’est pas trop gros (puisqu’il est copié intégralement dans une variable, c’est-à-dire dans la mémoire vive de l’ordinateur, il faut que la taille de celle-ci soit suffisante). — Notons que readline() est une fonction qui renvoie une chaîne de caractères, alors que la fonction readlines() renvoie une liste. À la fin du fichier, readline() renvoie une chaîne vide, tandis que readlines() renvoie une liste vide. 10. Suivant le système d’exploitation utilisé, le codage correspondant au marqueur de fin de ligne peut être différent. Il n’y a pas à se préoccuper de ces différences : lors des opérations d’écriture, Python utilise la convention en vigueur sur le système d’exploitation ; pour la lecture, Python interprète correctement chacun des codages. Fichiers 55 Se déplacer dans un fichier Les opérations de lecture/écriture se font de manière séquentielle, le « curseur » se positionnant toujours à la fin des données lues ou écrites. Il est cependant possible de naviguer à l’intérieur d’un fichier et de positionner le curseur à un endroit quelconque des données en spécifiant son décalage (en nombre de caractères) par rapport à l’origine du fichier à l’aide de la fonction seek() : >>> f = open("fichierTexte.txt", "r") >>> f.seek(14) # -> 14 caractères après le début >>> print(f.readline()) # on lit le reste de la ligne gne un >>> f.seek(38) # -> 38 caractères depuis le début >>> print(f.readlines()) # et on lit le reste du fichier [’ux\n’, ’Voici la ligne trois\n’, ’Voici la ligne quatre\n’] Exercice 1 Écrire une fonction copieFichier(source, destination) qui recopie le contenu d’un fichier texte nommé source dans un fichier nommé destination. Écrire cette fonction de deux manières différentes : soit en lisant le fichier source d’un bloc, soit ligne par ligne. Correction def copieFichier(source, destination): inFile = open(source, "r") total = inFile.read() inFile.close() outFile = open(destination, "w") outFile.write(total) outFile.close() def copieFichier_2(source, destination): inFile = open(source, "r") outFile = open(destination, "w") while 1: line = inFile.readline() if line == ’’: break outFile.write(line) inFile.close() outFile.close() Exercice 2 Reprendre le programme précédent qui effectue la recopie ligne par ligne et le modifier pour qu’il ne recopie que les lignes qui ne commencent pas par le caractère ’#’. 56 Fichiers Correction def copieFichier(source, destination): inFile = open(source, "r") outFile = open(destination, "w") while 1: line = inFile.readline() if line == ’’: break if line[0] != ’#’: outFile.write(line) inFile.close() outFile.close() Exercice 3 Écrire un programme qui génère automatiquement un fichier texte contenant les tables de multiplication de 2 à 30 (chacune d’entre elles incluant 20 termes seulement). Correction f=open("table.txt", "w") for i in range(2, 31): for j in range (1, 21): f.write(str(i*j)+’ ’) f.write(’\n’) f.close() Exercice 4 Écrire un programme qui recopie un fichier texte en triplant tous les espaces entre les mots. Correction def espaces(source, destination): inFile = open(source,"r") outFile= open(destination, "w") while 1: line = inFile.readline() if line == ’’: break outFile.write(line.replace(" ", " inFile.close() outFile.close() ")) Fichiers 57 Exercice 5 Un fichier texte est mis à disposition dont chaque ligne est la représentation d’une valeur numérique de type réel (mais sans exposants). Par exemple : 14.896 7894.6 123.278 Écrire un programme qui recopie ces valeurs dans un autre fichier en les arrondissant au nombre entier le plus proche (on pourra utiliser la fonction round()). Correction def nombresArrondis(source, destination): inFile = open(source, "r") outFile = open(destination, "w") while 1: line = inFile.readline() if line == ’’: break outFile.write(str(round(float(line))) + ’\n’) inFile.close() outFile.close() Exercice 6 Créer un fichier nommé "NotesGr1.txt" qui contiendra les notes d’algorithmique des étudiants du groupe 1 de première année. Le format est le suivant : chaque ligne correspond à un étudiant ; elle commence par son nom, suivi d’une tabulation, puis son prénom, et une tabulation précédera la note de l’étudiant (valeur décimale entre 0 et 20). Vous créerez quelques étudiants dans ce fichier en ne respectant aucun ordre particulier, ni alphabétique ni en fonction de la note. 1. Écrire une fonction lectureFichier(nom) qui ouvre le fichier texte dont le nom est passé en argument et renvoie une liste composée de toutes les lignes du fichier. 2. Écrire une fonction ecritureFichier(nom, liste) qui ouvre le fichier dont le nom est passé en argument et y écrit la liste de chaînes passée en paramètre, un élément par ligne. 3. Écrire une fonction triFichier() qui lit le fichier nommé "NotesGr1.txt" et crée un nouveau fichier "NotesGr1_trie.txt" qui contient les notes de tous les étudiants suivant le même format mais trié par ordre alphabétique de nom. On pourra bien sûr utiliser les deux fonctions précédemment définies. 4. Généraliser la fonction précédente en écrivant une fonction triNFichiers(N) qui lit N fichiers "NotesGr1.txt" à "NotesGrN.txt" et écrit sur le disque un unique fichier "NotesAmphi_trie.txt" compilant toutes les notes et toujours trié par ordre alphabétique de nom. 58 Fichiers 5. On souhaite maintenant effectuer le même travail mais en triant le fichier final suivant un ordre croissant des notes. Proposer des modifications aux deux premières fonctions pour ce faire. Les problèmes à résoudre sont : comment extraire la note de la ligne ? comment composer la liste de tous les étudiants pour effectuer le tri ? comment réécrire les informations dans le fichier final ? Correction def lectureFichier(nom): f=open(nom, "r") total = [] while 1: l = f.readline() if l == ’’: break total.append(l) f.close() return total def ecritureFichier(nom, liste): f=open(nom, "w") for l in liste: f.write(l) f.close() def triFichier(): total = lectureFichier("NotesGr1.txt") total.sort() ecritureFichier("NotesGr1_trie.txt", total) def triNFichiers(N): s = "NotesGr" total = [] for i in range(1,N+1): total += lectureFichier(s+str(i)+’.txt’) total.sort() ecritureFichier("NotesAmphi_trie.txt", total) Il faut créer une nouvelle liste dans laquelle chaque élément a maintenant la note en premier, ce qui va permettre d’effectuer le tri. Ensuite, la réécriture oblige de nouveau à remettre les éléments dans le bon ordre. def lectureFichier2(nom): f=open(nom, "r") total = [] while 1: l = f.readline() if l == ’’: break Fichiers L = l.split(’\t’) newLL = [float(L[2])] + [L[0]] + [L[1]] total.append(newLL) f.close() return total def ecritureFichier2(nom, liste): f=open(nom, "w") for l in liste: f.write(l[1]+’\t’+l[2]+’\t’+str(l[0])+’\n’) f.close() def triNFichiers(N): s = "NotesGr" total = [] for i in range(1,N+1): total += lectureFichier2(s+str(i)+’.txt’) total.sort() ecritureFichier2("NotesAmphi_trie.txt", total) triNFichiers(2) 59