## page was renamed from TestMEEF = Des exercices de Python pour se tester = Vous trouverez ci-dessous quelques exercices basiques, qui vous permettront de vérifier si vous avez le niveau attendu en Python pour cette UE. En genéral, essayez de répondre d’abord sans tester sur machine, puis vérifiez. Si vous avez un doute, vous pouvez utiliser [[http://pythontutor.com/index.html|Python Tutor]] pour visualiser le fonctionnement de votre programme. Si quelque chose coince, '''criez !''' On reviendra dessus. Le but est qu’à la fin de la séance, plus rien ne coince. Certains termineront vite, et pourront alors se perfectionner avec [[http://ens-info.irem.univ-mrs.fr/wiki/Codes%20de%20C%C3%A9sar%20et%20de%20Vigen%C3%A8re|un TP de cryptographie]], [[http://ens-info.irem.univ-mrs.fr/wiki/Dessiner%20des%20graphes%20de%20fonctions%20%28et%20plein%20d%E2%80%99autres%20choses%29|tester la bibliothèque de calcul scientifique pylab]] (si elle est disponible), ou [[http://ens-info.irem.univ-mrs.fr/wiki/Recherche%20de%20s%C3%A9quences%20codantes%20dans%20un%20g%C3%A9nome|faire joujou avec le génome de Bacillus subtilis subsp. subtilis str. 168]]. == Affectations et types == Après chacun des blocs d’instructions suivants, quel est la valeur de `a` ? Quel est le type de cette valeur ? {{{#!highlight python3 a = 2 a = a+1 }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 2 >>> a = a+1 >>> a, type(a) (3, int)}}} }}}} {{{#!highlight python3 a = 2 a = a*a a = a*a a = a*a }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 2 >>> a = a*a >>> a = a*a >>> a = a*a >>> a, type(a) (256, int)}}} }}}} {{{#!highlight python3 a = 2 a = a//2 a = a//2 }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 2 >>> a = a//2 >>> a = a//2 >>> a, type(a) (0, int)}}} }}}} {{{#!highlight python3 a = 2 a = a/2 a = a/2 }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 2 >>> a = a/2 >>> a = a/2 >>> a, type(a) (0.5, float)}}} }}}} {{{#!highlight python3 a = 1 a = 0 <= a }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 1 >>> a = 0 <= a >>> a, type(a) (True, bool)}}} }}}} {{{#!highlight python3 a = False a = a == a b = True a = a and b }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = False >>> a = a == a >>> b = True >>> a = a and b >>> a, type(a) (True, bool)}}} }}}} {{{#!highlight python3 def f(x): x = x+1 a = f(1) }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> def f(x): ... x = x+1 ... >>> a = f(1) >>> a, type(a) (None, NoneType)}}} }}}} {{{#!highlight python3 def f(x): return x+1 a = f(1) }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> def f(x): ... return x+1 ... >>> a = f(1) >>> a, type(a) (2, int)}}} }}}} {{{#!highlight python3 a = 0,1 + 0,1 }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 0,1 + 0,1 >>> a, type(a) ((0,1,1), tuple)}}} }}}} {{{#!highlight python3 a = 0,1 a = a+a a = a[3] }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = 0,1 >>> a = a+a >>> a = a[3] >>> a, type(a) (1, int)}}} }}}} {{{#!highlight python3 a = [0,1] a = [a] a = a+a }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = [0,1] >>> a = [a] >>> a = a+a >>> a, type(a) ([[0,1],[0,1]], list)}}} }}}} {{{#!highlight python3 a = [0] a = [a]+a a = [a]+a }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = [0] >>> a = [a]+a >>> a = [a]+a >>> a, type(a) ([[[0],0],[0],0], list)}}} }}}} {{{#!highlight python3 a = [1,2,3] a = a[0] == a[len(a)-1] }}} {{{{#!wiki comment/dotted {{{#!highlight pycon >>> a = [1,2,3] >>> a = a[0] == a[len(a)-1] >>> a, type(a) (False, bool)}}} }}}} == Boucles == Que calcule chacune des fonctions suivantes en supposant qu’on donne toujours un argument de type `int` ? {{{#!highlight python3 def f(n): x = 0 for i in range(n): x = i return x }}} {{{{#!wiki comment/dotted Ça renvoie `0` si `n>0` (car on retourne `x` et donc la valeur courante de `i` dès la première itération) et `None` sinon (car la boucle n’est pas empruntée donc rien n’est renvoyé). }}}} {{{#!highlight python3 def f(n): x = 0 for i in range(n): x = i return x }}} {{{{#!wiki comment/dotted Ça renvoie `n-1` si `n>0` (la dernière valeur de `i` affectée à `x` dans la boucle) et `0` sinon (car la boucle n’est pas empruntée). }}}} {{{#!highlight python3 def f(n): l = [] for i in range(1,n): l = l + [n-i] return l }}} {{{{#!wiki comment/dotted La boucle commence avec `i==1`. À chaque tour de boucle, on démarre avec `l` qui contient les entiers de `n-1` à `n-i+1` et on ajoute `n-i` à la fin de la liste. Quand on sort de la boucle, on vient donc d’ajouter `n-(n-1)`, c’est-à-dire `1`. Donc `f(n)` renvoie la liste des entiers dans l’ordre décroissant de `n-1` à `1` si `n>1` et la liste vide sinon. }}}} {{{#!highlight python3 def f(n): x = 0 s = 0 while x < n: s = s + x x = x + 1 return s }}} {{{{#!wiki comment/dotted On entre dans la boucle avec `x==0` et `s==0`. À chaque tour de boucle, on ajoute la valeur courante de `x` puis on incrémente `x`. On sort quand `x` vaut `n`. On calcule donc la somme des `x` pour `x` allant de `0` jusqu’à `n-1` (c’est-à-dire `(n*(n-1))//2`). On peut le montrer formellement: * l’invariant de boucle est ''`s` contient la somme des entiers de `0` à `x-1` (inclus)'', * c’est vrai à l’entrée de la boucle, * c’est préservé par le corps de la boucle, * donc c’est vrai quand on sort de la boucle, * de plus on sort de la boucle avec `x==n`. }}}} {{{#!highlight python3 def g(n): x = 0 s = 0 while x < n: x = x + 1 s = s + x return s }}} {{{{#!wiki comment/dotted On montre de la même manière que ça calcule la somme des `x` pour `x` allant de `1` jusqu’à `n` (c’est-à-dire `(n*(n+1))//2`). }}}} == Erreurs == Chacun des blocs suivants provoque une erreur: pourquoi? {{{#!highlight python3 x = 12 print('le résultat est '+x) }}} {{{{#!wiki comment/dotted On ne peut pas appliquer `+` entre une chaîne et un nombre (mais avez-vous essayé avec `*` ?). Pour corriger, on peut utiliser le comportement de `print` avec plusieurs arguments (affichage de chaque argument, avec des espaces intercalés): {{{#!highlight python3 x = 12 print('le résultat est', x) }}} ou construire la chaîne à la main: {{{#!highlight python3 x = 12 print('le résultat est '+str(x)) }}} }}}} {{{#!highlight python3 résultat = 0 for i in range(10): résultat = résultat + 1/i }}} {{{{#!wiki comment/dotted La première itération fait une division par 0. }}}} {{{#!highlight python3 l = [1,2,3] somme = 0 for i in range(1,len(l)+1): somme = somme + l[i] }}} {{{{#!wiki comment/dotted La dernière itération se fait avec `i==len(l)` et `l[len(l)]` n’est pas défini. }}}} {{{#!highlight python3 def double (x): x+x a=1 a=double(a) a=double(a) }}} {{{{#!wiki comment/dotted Comme il n’y a pas de return, après le premier `a=double(a)`, `a` vaut `None` et ça plante quand on veut calculer `a+a` dans le deuxième `double(a)`. }}}} Celui-là ne provoque pas d’erreur mais il est problématique : pourquoi ? {{{#!highlight python3 valeurs = [1,2,3,4] somme = 0 i = 0 while i0: c = str(a % b) + c a = a // b return c }}} * Que renvoient `f(-1,10)`, `f(1,3)`, `f(16,2)`, `f(123,10)` ? * Pourquoi ne faut-il pas appeler `f(10,1)` ? * En général, que calcule `f` ? * Définissez une fonction `g` telle que `g(f(a,b),b) == a` dès que `a` est un entier naturel et `b` est un entier compris (au sens large) entre `2` et `10` (vous pouvez réfléchir à ce qu’il faudrait faire quand `b>10`). {{{{#!wiki comment/dotted Pour les valeurs, on obtient: {{{#!highlight pycon >>> f(-1,10), f(1,3), f(16,2), f(123,10) ('', '1', '10000', '123') }}} Notez que la première valeur est la chaîne vide. Si on appelle `f(10,1)`, ça boucle indéfiniment. En effet, on boucle tant que `a>0`, or si `b==1`, l’instruction `a = a // b` ne change pas la valeur de `a`. L’expression `f(a,b)` renvoie l’écriture de `a` en base `b`, calculée par l’algorithme usuel pour obtenir les chiffres successifs: * `a % b` est le chiffre de poids faible de l’écriture de `a` en base `b` * on continue avec `a // b`, qui est le nombre obtenu en éliminant le chiffre de poids faible. Une version plus lisible serait: {{{#!highlight python3 def f(nombre,base): écriture = '' while nombre>0: écriture = str(nombre % base) + écriture nombre = nombre // base return écriture }}} Notez que dans le cas particulier où `a == 0`, on obtient la chaîne vide: en effet, c’est bien la valeur qui correspond à la définition ''stricto sensu'', et on n’écrit usuellement le chiffre `0` que parce qu’il faut bien écrire quelque chose… Pour inverser `f` il faut calculer la valeur d’un nombre en base `b` à partir de son écriture. Une solution possible : {{{#!highlight python3 def g(écriture,base): nombre = 0 for chiffre in écriture: nombre = nombre * base + int(chiffre) return nombre }}} Il y a par contre un ''bug'' dans cette approche : pour les chiffres, on est limité à la représentation décimale ''via'' la fonction de conversion `str`. En l’état, ça ne fonctionne donc que pour une base inférieure ou égale à 10. Si on essaie avec `b==16` par exemple, le programme ne peut pas inventer tout seul la suite des chiffres `0,1,...,9,A,B,C,D,E,F`. Pour faire les choses plus proprement et sans limitation de la base, il faudrait travailler avec des listes. Ça donne les fonctions : {{{#!highlight python3 def f(nombre,base): écriture = [] while nombre>0: écriture = [nombre % base] + écriture nombre = nombre // base return écriture }}} et {{{#!highlight python3 def g(écriture,base): nombre = 0 for chiffre in écriture: nombre = nombre * base + chiffre return nombre }}} qui calculent le codage et le décodage d’un nombre positif quelconque en liste de nombres strictement inférieurs à `b`. }}}} Notez que vous pouvez afficher les solutions aux exercices en cliquant sur le bouton `Commentaires` dans la barre de menu.