18 | Ce chapitre concerne l’itération, qui permet d’exécuter un bloc d’instructions à plusieurs reprises.
19 | Nous avons vu une sorte d’itération, en utilisant la récursivité, dans la section 5.8. Nous avons aussi vu un autre type, en utilisant un
20 | boucle for, dans la section 4.2. Dans ce chapitre, nous verrons un autre type, en utilisant une instruction while.
21 | Mais je veux d’abord en dire un peu plus sur l’affectation de variables.
Comme vous avez pu le constater, il est légal de confier plusieurs affectations à la même 24 | variable. Une nouvelle affectation fait qu’une variable existante se réfère à une nouvelle valeur (et arrête 25 | de faire référence à l’ancienne valeur).
26 |>>> x = 5
27 | >>> x
28 | 5
29 | >>> x = 7
30 | >>> x
31 | 7
32 |
33 |
34 | La première fois que nous affichons x, sa valeur est 5; la deuxième fois, sa valeur est 7.
35 |Le dessin 7.1 montre à quoi ressemble la réaffectation dans un diagramme d’état.
36 |À ce stade, je veux aborder une source commune de confusion. Parce que Python utilise le 37 | signe égal (=) pour l’affectation, il est tentant d’interpréter un énoncé comme a = b comme une proposition mathématique d’égalité; c’est-à-dire que a et b sont égaux. Mais cette interprétation est fausse. 38 | Tout d’abord, l’égalité est une relation symétrique et l’affectation ne l’est pas. Par exemple, en mathématiques, si a = 7 alors 7 = a. Mais en Python, l’instruction a = 7 est légale de 7 = a 39 | est faux. 40 | De plus, en mathématiques, une proposition d’égalité est vraie ou faux pour tous les temps. Si a = 41 | b maintenant, alors b sera toujours égal à a. En Python, une instruction d’affectation peut faire deux 42 | variables égales, mais ils ne doivent pas rester comme ça:
43 |>>> a = 5
44 | >>> b = a # a and b are now equal
45 | >>> a = 3 # a and b are no longer equal
46 | >>> b
47 | 5
48 |
49 |
50 | La troisième ligne change la valeur de a mais ne change pas la valeur de b, donc elles ne sont pas 51 | plus égal 52 | La réaffectation des variables est souvent utile, mais vous devez l’utiliser avec prudence. Si les valeurs des 53 | variables changent fréquemment, cela peut rendre le code difficile à lire et à déboguer.
54 |Figure 7.1: Diagramme d’état.
56 |Un type courant de réaffectation est une mise à jour, où la nouvelle valeur de la variable dépend 58 | sur l’ancien
59 |>>> x = x + 1
60 |
61 |
62 | Cela signifie “obtenir la valeur actuelle de x, ajouter un, puis mettre à jour x avec la nouvelle valeur.” 63 | Si vous essayez de mettre à jour une variable qui n’existe pas, vous obtenez une erreur, car Python évalue 64 | le côté droit avant d’assigner une valeur à x:
65 |>>> x = x + 1
66 | NameError: name 'x' is not defined
67 |
68 |
69 | Avant de pouvoir mettre à jour une variable, vous devez l’initialiser, généralement avec une affectation simple:
70 |>>> x = 0
71 | >>> x = x + 1
72 |
73 |
74 | La mise à jour d’une variable en ajoutant 1 est appelée un incrément; soustraire 1 est appelé décrément.
75 |Les ordinateurs sont souvent utilisés pour automatiser des tâches répétitives. Répéter des tâches identiques ou similaires 77 | sans faire d’erreurs est quelque chose que les ordinateurs font bien et que les gens font mal. Dans un 78 | programme informatique, la répétition est aussi appelée itération. 79 | Nous avons déjà vu deux fonctions, countdown et print_n, qui itèrent en utilisant la récursivité. 80 | Comme l’itération est si courante, Python fournit des fonctionnalités de langage pour le rendre plus facile. Un 81 | est la déclaration for que nous avons vue à la section 4.2. Nous y reviendrons plus tard. 82 | Une autre est la boucle while. Voici une version du compte à rebours qui utilise une instruction while:
83 |def countdown(n):
84 | while n > 0:
85 | print(n)
86 | n = n - 1
87 | print('Blastoff!')
88 |
89 |
90 | Vous pouvez presque lire la déclaration while comme si c’était l’anglais. Cela signifie que “Alors que n est plus grand 91 | que 0, affiche la valeur de n puis décrémente n. Lorsque vous arrivez à 0, affichez le mot 92 | blastoff”
93 |Plus formellement, voici le déroulement de l’exécution: 94 | 1. Déterminez si la condition est vraie ou fausse. 95 | 2. Si la valeur est false, quittez l’instruction while et continuez l’exécution à l’instruction suivante. 96 | 3. Si la condition est vraie, lancez le corps et retournez à l’étape 1.
97 |Ce type de flux est appelé une boucle car la troisième étape est bouclée vers le haut. 98 | Le corps de la boucle devrait changer la valeur d’une ou plusieurs variables pour que la condition 99 | devient finalement faux et la boucle se termine. Sinon, la boucle se répètera pour toujours, 100 | qui s’appelle une boucle infinie. Une source d’amusement sans fin pour les informaticiens 101 | est l’observation que les instructions sur le shampooing, “Lather, rinse, repeat”, est une boucle 102 | infinie. 103 | Dans le cas du compte à rebours, on peut prouver que la boucle se termine: si n est zéro ou négatif, le 104 | boucle ne fonctionne jamais. Sinon, n diminue chaque fois à travers la boucle, donc finalement nous 105 | doivent arriver à 0. 106 | Pour d’autres boucles, ce n’est pas si facile à dire. Par exemple:
107 |def sequence(n):
108 | while n != 1:
109 | print(n)
110 | if n % 2 == 0: # n is even
111 | n = n / 2
112 | else: # n is odd
113 | n = n * 3 + 1
114 |
115 |
116 | La condition pour cette boucle est n! = 1, donc la boucle continuera jusqu’à ce que n soit 1, ce qui rend 117 | la condition fausse. 118 | À chaque fois dans la boucle, le programme affiche la valeur de n et vérifie ensuite si 119 | c’est pair ou impair. Si c’est pair, n est divisé par 2. S’il est impair, la valeur de n est remplacée par 120 | n * 3 + 1. Par exemple, si l’argument passé à la séquence est 3, les valeurs résultantes de n 121 | sont 3, 10, 5, 16, 8, 4, 2, 1. 122 | Comme n augmente et diminue parfois, il n’ya pas de preuve évidente que n 123 | atteindra 1, ou que le programme se termine. Pour certaines valeurs particulières de n, nous pouvons prouver 124 | la términaison. Par exemple, si la valeur de départ est une puissance de deux, n sera pair à 125 | chaque fois dans la boucle jusqu’à ce qu’il atteigne 1. L’exemple précédent se termine par une telle séquence, 126 | à partir de 16. 127 | La question difficile est de savoir si nous pouvons prouver que ce programme se termine pour toutes les valeurs positives de n. Jusqu’à présent, personne n’a été capable de le prouver ou de le réfuter! Voyez collatz conjecture)
128 |En guise d’exercice, réécrivez la fonction print_n de la section 5.8 en utilisant l’itération au lieu de 129 | récursivité.
130 |Parfois, vous ne savez pas qu’il est temps de terminer une boucle jusqu’à ce que vous atteigniez la moitié du corps. 132 | Dans ce cas, vous pouvez utiliser l’instruction break pour sortir de la boucle. 133 | Par exemple, supposons que vous souhaitiez saisir les informations de l’utilisateur jusqu’à ce qu’elles soient saisies. Vous pourriez 134 | écrire:
135 |while True:
136 | line = input('> ')
137 | if line == 'done':
138 | break
139 | print(line)
140 |
141 | print('Done!')
142 |
143 |
144 | La condition de la boucle est True, ce qui est toujours vrai, donc la boucle s’exécute jusqu’à ce qu’elle atteigne la déclaration de 145 | rupture. 146 | À chaque fois, l’utilisateur est invité à choisir une option. Si l’utilisateur type ‘done’ (terminé), l’ 147 | instruction break quitte la boucle. Sinon, le programme reimprime ce que l’utilisateur type et 148 | retourne au sommet de la boucle. Voici un exemple:
149 |> not done
150 | not done
151 | > done
152 | Done!
153 |
154 |
155 | Cette façon d’écrire des boucles est commune car vous pouvez vérifier la condition n’importe où 156 | dans la boucle (pas seulement en haut) et vous pouvez exprimer la condition d’arrêt de manière affirmative (“arretez 157 | quand cela se produit “) plutôt que négativement (” continuez jusqu’à ce que cela arrive “).
158 |Les boucles sont souvent utilisées dans les programmes qui calculent des résultats numériques en commençant par une réponse approximative et en l’améliorant de manière itérative. 160 | Par exemple, une méthode de calcul des racines carrées est la méthode de Newton. Supposons que vous 161 | voulez savoir la racine carrée de a. Si vous commencez avec presque n’importe quelle estimation, x, vous pouvez calculer une meilleure estimation avec la formule suivante:
162 |y = (x + a/x) / 2
163 |
164 |
165 | Par exemple, si a est 4 et que x est 3:
166 |>>> a = 4
167 | >>> x = 3
168 | >>> y = (x + a / x) / 2
169 | >>> y
170 | 2.16666666667
171 |
172 |
173 | Le résultat est plus proche de la réponse correcte (4 = 2). Si nous répétons le processus avec le nouveau 174 | estimation, il devient encore plus proche:
175 |>>> x = y
176 | >>> y = (x + a / x) / 2
177 | >>> y
178 | 2.00641025641
179 |
180 |
181 | Après quelques mises à jour supplémentaires, l’estimation est presque exacte:
182 |>>> x = y
183 | >>> y = (x + a / x) / 2
184 | >>> y
185 | 2.00001024003
186 | >>> x = y
187 | >>> y = (x + a / x) / 2
188 | >>> y
189 | 2.00000000003
190 |
191 |
192 | En général, nous ne savons pas combien de temps il faut pour arriver à la bonne réponse, 193 | mais on sait quand on arrive là-bas car le devis cesse de changer:
194 |>>> x = y
195 | >>> y = (x + a / x) / 2
196 | >>> y
197 | 2.0
198 | >>> x = y
199 | >>> y = (x + a / x) / 2
200 | >>> y
201 | 2.0
202 |
203 |
204 | Lorsque y == x, on peut s’arrêter. Voici une boucle qui commence par une estimation initiale, x, et l’améliore jusqu’à ce qu’elle cesse de changer:
205 |while True:
206 | print(x)
207 | y = (x + a/x) / 2
208 | if y == x:
209 | break
210 | x = y
211 |
212 |
213 | Pour la plupart des valeurs de a, cela fonctionne bien, mais en général, il est dangereux de tester l’égalité des flottants. 214 | Les valeurs à virgule flottante sont approximativement correctes: la plupart des nombres rationnels, comme 1/3, et 215 | les nombres irrationnels, comme 2, ne peuvent pas être représentés exactement avec un flottant. 216 | Plutôt que de vérifier si x et y sont exactement égaux, il est préférable d’utiliser la fonction intégrée abs pour calculer la valeur absolue, ou l’ampleur, de la différence entre eux:
217 |if abs(y-x) < epsilon: 218 | break 219 | Où epsilon a une valeur comme 0.0000001 qui détermine la proximité est assez proche.
220 |La méthode de Newton est un exemple d’algorithme: c’est un processus mécanique pour résoudre un 222 | catégorie de problèmes (dans ce cas, calcul des racines carrées).n
223 |Pour comprendre ce qu’est un algorithme, il peut être utile de commencer par quelque chose qui n’est pas un 224 | algorithme. Lorsque vous avez appris à multiplier des nombres à un chiffre, vous avez probablement mémorisé 225 | la table de multiplication. En effet, vous avez mémorisé 100 solutions spécifiques. Ce genre de 226 | connaissance n’est pas algorithmique. 227 | Mais si vous étiez “paresseux”, vous avez peut-être appris quelques astuces. Par exemple, pour trouver le 228 | produit de n et 9, vous pouvez écrire n-1 comme premier chiffre et 10-n comme deuxième chiffre. 229 | Cette astuce est une solution générale pour multiplier un nombre à un chiffre par 9. C’est un 230 | algorithme! 231 | De même, les techniques que vous avez apprises pour l’addition avec transport, la soustraction avec emprunt et la division longue sont toutes des algorithmes. L’une des caractéristiques des algorithmes est que 232 | ils n’ont besoin d’aucune intelligence pour effectuer. Ce sont des processus mécaniques où 233 | chaque étape découle de la dernière selon un ensemble simple de règles. 234 | L’exécution d’algorithmes est ennuyeuse, mais leur conception est intéressante, un défi intellectuel et constitue un élément central de l’informatique. 235 | Certaines des choses que les gens font naturellement, sans difficulté, ni pensée consciente, sont: 236 | le plus difficile à exprimer algorithmiquement. Comprendre le langage naturel est un bon exemple. 237 | Nous le faisons tous, mais jusqu’à présent, personne n’a pu expliquer comment nous le faisons, du moins pas sous la forme 238 | d’un algorithme.
239 |Lorsque vous commencez à écrire de plus gros programmes, vous risquez de devoir passer plus de temps à déboguer. Plus de code signifie plus de chances de faire une erreur et plus d’endroits où les bogues peuvent se cacher. 241 | Un moyen de réduire votre temps de débogage est le “débogage par bissection”. Par exemple, s’il y a 242 | sont 100 lignes dans votre programme et vous les vérifiez un par un, cela prendrait 100 étapes. 243 | Au lieu de cela, essayez de briser le problème en deux. Regardez au milieu du programme, ou à proximité, pour 244 | une valeur intermédiaire que vous pouvez vérifier. Ajouter un relevé d’impression (ou autre chose qui a un 245 | effet vérifiable) et exécuter le programme. 246 | Si la vérification à mi-parcours est incorrecte, il doit y avoir un problème dans la première moitié du programme. 247 | Si c’est correct, le problème est dans la seconde moitié. 248 | Chaque fois que vous effectuez une vérification comme celle-ci, vous divisez par deux le nombre de lignes à rechercher. 249 | Après six étapes (moins de 100), vous seriez réduit à une ou deux lignes de code, 250 | au moins en théorie. 251 | En pratique, il n’est pas toujours évident de savoir ce que le “milieu du programme” est et n’est pas toujours possible de vérifier. Cela n’a aucun sens de compter les lignes et de trouver le point médian exact. Au lieu, 252 | penser à des endroits du programme où il peut y avoir des erreurs et des endroits faciles à 253 | mettre un checkpoint. Ensuite, choisissez un endroit où vous pensez que les chances sont à peu près les mêmes 254 | le bug est avant ou après la vérification.
255 |réaffectation: attribuer une nouvelle valeur à une variable qui existe déjà.
259 |update: Affectation où la nouvelle valeur de la variable dépend de l’ancienne.
262 |initialization: une affectation qui donne une valeur initiale à une variable qui sera mise à jour.
265 |increment: une mise à jour qui augmente la valeur d’une variable (souvent par une seule).
268 |décrément: une mise à jour qui diminue la valeur d’une variable.
271 |iteration: exécution répétée d’un ensemble d’instructions à l’aide d’un appel de fonction récursif 274 | ou une boucle.
275 |boucle infinie: boucle dans laquelle la condition de terminaison n’est jamais satisfaite.
278 |algorithme: un processus général pour résoudre une catégorie de problèmes.
281 |Exercice 1
285 |Copiez la boucle de la section 7.5 et encapsulez-la dans une fonction appelée mysqrt 286 | prend un comme paramètre, choisit une valeur raisonnable de x et renvoie une estimation de la racine carrée de 287 | une. 288 | Pour le tester, écrivez une fonction nommée test_square_root qui imprime un tableau comme celui-ci:
289 |a mysqrt(a) math.sqrt(a) diff
290 | - --------- ------------ ----
291 | 1.0 1.0 1.0 0.0
292 | 2.0 1.41421356237 1.41421356237 2.22044604925e-16
293 | 3.0 1.73205080757 1.73205080757 0.0
294 | 4.0 2.0 2.0 0.0
295 | 5.0 2.2360679775 2.2360679775 0.0
296 | 6.0 2.44948974278 2.44948974278 0.0
297 | 7.0 2.64575131106 2.64575131106 0.0
298 | 8.0 2.82842712475 2.82842712475 4.4408920985e-16
299 | 9.0 3.0 3.0 0.0
300 |
301 |
302 | La première colonne est un nombre, a; la deuxième colonne est la racine carrée d’un calcul avec mysqrt; 303 | la troisième colonne est la racine carrée calculée par math.sqrt; la quatrième colonne est la valeur absolue 304 | de la différence entre les deux estimations.
305 |Exercice 2
306 |La fonction intégrée eval prend une chaîne et l’évalue à l’aide de l’interpréteur Python. Par exemple:
307 |>>> eval('1 + 2 * 3')
308 | 7
309 | >>> import math
310 | >>> eval('math.sqrt(5)')
311 | 2.2360679774997898
312 | >>> eval('type(math.pi)')
313 | <class 'float'>
314 |
315 |
316 | Ecrire une fonction appelée eval_loop qui invite de manière itérative l’utilisateur, prend l’entrée résultante et 317 | l’évalue en utilisant eval et imprime le résultat. 318 | Il doit continuer jusqu’à ce que l’utilisateur entre “done”, puis renvoyer la valeur de la dernière expression 319 | évalué.
320 |Exercice 7.3.
321 |Le mathématicien Srinivasa Ramanujan a trouvé une série infinie qui peut être utilisée pour 322 | générer une approximation numérique de 1 / π:
323 | ∞
324 | 1/π = 2√2 / 9801 ∑ (4k)!(1103+26390k) / (k!)4 3964k
325 | k=0
326 |
327 |
328 | Ecrivez une fonction appelée estimation_pi qui utilise cette formule pour calculer et renvoyer une estimation de 329 | π. Il devrait utiliser une boucle while pour calculer les termes de la sommation jusqu’à ce que le dernier terme soit plus petit que 330 | 1e-15 (qui est la notation Python pour 10-15). Vous pouvez vérifier le résultat en le comparant à math.pi. 331 | Solution: http://thinkpython2.com/code/pi.py
332 | 333 | 334 | 335 |