Outils Pour

Identification

Infoforall

9 - Boucles Bornées


Voyons maintenant comment limiter la taille des fonctions lorsqu'on doit faire des choses répétitives.

Pour faire s'afficher fois la même chose, on peut écrire ce programme :

1 2 3 4 5 6 7 8 9 10 11 12 13 14
# Déclaration des CONSTANTES TEXTE = "J'aime bien les copier coller !" # Programme principal print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE) print(TEXTE)

Heureusement, on peut faire mieux ! Nous allons voir ceci aujourd'hui :

1 2 3 4 5 6
# Déclaration des CONSTANTES TEXTE = "J'aime bien les copier coller !" # Programme principal for _ in range(10): print(TEXTE)

Evaluation ✎ : questions 14-18-19A-20

Evaluation ✌ : questions 09C-10-19B

Documents de cours : open document ou pdf

1 - Introduction et Cours

Voyons comment tracer une étoile colorée avec Turtle.

Nous allons voir que les copier-coller ne sont pas pratiques en programmation.

Toute cette partie est plutôt destinée à être lue en classe, en présentation de l'intérêt des boucles. Vous n'êtes pas obligé de la lire si vous travaillez en autonomie.

Intro-01° Utiliser le programme ci-dessous pour vérifier qu'il trace bien une étoile. 100 lignes...

Le programme :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
# 1 - Importations import turtle as trt # 2 - CONSTANTES FOND = "black" COULEUR_ETOILE = "yellow" TAILLE_ETOILE = 100 EPAISSEUR_RAYON = 4 # 3 - Programme principal trt.bgcolor(FOND) # On définit un fond coloré noir crayon = trt.Turtle() # On définit un crayon crayon.color(COULEUR_ETOILE) crayon.pensize(EPAISSEUR_RAYON) # Rayon d'angle 0° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(0) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 30° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(30) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 60° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(60) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 90° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(90) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 120° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(120) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 150° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(150) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 180° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(180) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 210° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(210) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 240° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(240) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 270° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(270) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 300° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(300) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance # Rayon d'angle 330° crayon.penup() crayon.goto(0, 0) # on part au point de départ crayon.pendown() crayon.setheading(330) # on s'oriente vers la droite crayon.forward(TAILLE_ETOILE) # on affiche de la bonne distance crayon.hideturtle()

Intro-02° Utiliser le programme ci-dessous pour vérifier qu'il trace bien une étoile. Moins de lignes puisqu'on remarque qu'on utilise souvent les mêmes instructions à quelques valeurs près. Autant créer une fonction trait() qui réalise ces instructions lorsqu'on l'appele.

29 30 31 32 33 34 35 36 37 38 39 40
trait(crayon, 30, TAILLE_ETOILE, (0,0)) # Rayon d'angle 0° trait(crayon, 30, TAILLE_ETOILE, (0,0)) # Rayon d'angle 30° trait(crayon, 60, TAILLE_ETOILE, (0,0)) # Rayon d'angle 60° trait(crayon, 90, TAILLE_ETOILE, (0,0)) # Rayon d'angle 90° trait(crayon, 120, TAILLE_ETOILE, (0,0)) # Rayon d'angle 120° trait(crayon, 150, TAILLE_ETOILE, (0,0)) # Rayon d'angle 150° trait(crayon, 180, TAILLE_ETOILE, (0,0)) # Rayon d'angle 180° trait(crayon, 210, TAILLE_ETOILE, (0,0)) # Rayon d'angle 210° trait(crayon, 240, TAILLE_ETOILE, (0,0)) # Rayon d'angle 240° trait(crayon, 270, TAILLE_ETOILE, (0,0)) # Rayon d'angle 270° trait(crayon, 300, TAILLE_ETOILE, (0,0)) # Rayon d'angle 300° trait(crayon, 330, TAILLE_ETOILE, (0,0)) # Rayon d'angle 330°

40 lignes, c'est déjà mieux.

Le programme :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
# 1 - Importations import turtle as trt # 2 - CONSTANTES FOND = "black" COULEUR_ETOILE = "yellow" TAILLE_ETOILE = 100 EPAISSEUR_RAYON = 4 # 3 - Déclaration de fonction def trait(feutre, angle, distance, coord): crayon.penup() crayon.goto(coord[0], coord[1]) # on part au point de départ crayon.pendown() crayon.setheading(angle) # on s'oriente vers la droite crayon.forward(distance) # on affiche de la bonne distance # 3 - Programme principal trt.bgcolor(FOND) # On définit un fond coloré noir crayon = trt.Turtle() # On définit un crayon crayon.color(COULEUR_ETOILE) crayon.pensize(EPAISSEUR_RAYON) trait(crayon, 30, TAILLE_ETOILE, (0,0)) # Rayon d'angle 0° trait(crayon, 30, TAILLE_ETOILE, (0,0)) # Rayon d'angle 30° trait(crayon, 60, TAILLE_ETOILE, (0,0)) # Rayon d'angle 60° trait(crayon, 90, TAILLE_ETOILE, (0,0)) # Rayon d'angle 90° trait(crayon, 120, TAILLE_ETOILE, (0,0)) # Rayon d'angle 120° trait(crayon, 150, TAILLE_ETOILE, (0,0)) # Rayon d'angle 150° trait(crayon, 180, TAILLE_ETOILE, (0,0)) # Rayon d'angle 180° trait(crayon, 210, TAILLE_ETOILE, (0,0)) # Rayon d'angle 210° trait(crayon, 240, TAILLE_ETOILE, (0,0)) # Rayon d'angle 240° trait(crayon, 270, TAILLE_ETOILE, (0,0)) # Rayon d'angle 270° trait(crayon, 300, TAILLE_ETOILE, (0,0)) # Rayon d'angle 300° trait(crayon, 330, TAILLE_ETOILE, (0,0)) # Rayon d'angle 330° crayon.hideturtle()

Intro-03° On se rend compte que les appels aux fonctions sont presque les mêmes : la seule chose qui change, c'est la valeur de l'angle ! Il est tant de demander à Python de faire la même chose, ou presque.

Nous allons lui demander poliment de faire la même chose pour un angle de 0°, puis d'augmenter de 30° à chaque fois qu'il refait un tour de boucle. Il ne devra par contre par refaire 360° puisque cet angle correspond à l'angle 0° en réalité : nous avons fait un tour complet.

28 29
for angle in range(0, 360, 30): trait(crayon, angle, TAILLE_ETOILE, (0,0)) # angle va avoir plusieurs valeurs

Le programme :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
# 1 - Importations import turtle as trt # 2 - CONSTANTES FOND = "black" COULEUR_ETOILE = "yellow" TAILLE_ETOILE = 100 EPAISSEUR_RAYON = 4 # 3 - Déclaration de fonction def trait(feutre, angle, distance, coord): crayon.penup() crayon.goto(coord[0], coord[1]) # on part au point de départ crayon.pendown() crayon.setheading(angle) # on s'oriente vers la droite crayon.forward(distance) # on affiche de la bonne distance # 3 - Programme principal trt.bgcolor(FOND) # On définit un fond coloré noir crayon = trt.Turtle() # On définit un crayon crayon.color(COULEUR_ETOILE) crayon.pensize(EPAISSEUR_RAYON) for angle in range(0, 360, 30): trait(crayon, angle, TAILLE_ETOILE, (0,0)) # angle va avoir plusieurs valeurs crayon.hideturtle()

Le cours n'est pas destiné à être lu d'un bloc non plus. Vous pouvez passer si vous travaillez en autonomie.

1 - Boucle POUR basique : réaliser plusieurs fois la même action

Pour réaliser plusieurs fois la même série d'actions, il suffit d'utiliser une boucle bornée POUR, qu'on déclare à l'aide du mot-clé for en Python.

1 2 3 4 5 6 7
print("Hors boucle") for _ in range(5): print("Action de boucle 1") print("Action de boucle 2") print("Hors boucle")

Déroulé du programme :

  • L1
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • L7

On retrouve le même principe qu'avec les déclarations de fonction :

  1. Présence d'un point double ":" à la fin de la ligne de déclaration.
  2. Indentation pour indiquer quelles instructions appartiennent au bloc de la boucle : lignes 4 et 5 ici.
  3. La fin de la boucle est indiquée par le retour à la tabulation normale.

La syntaxe for _ in range(50) signale qu'on veut réaliser la boucle 50 fois.

2 - Boucle et variable de boucle

2A - Variable de boucle

On peut utiliser une boucle POUR de façon à

  1. Faire plusieurs fois la même chose (voir 1). On donne alors souvent le nom _ à la variable de boucle (pour indiquer qu'elle ne sert à rien de particulier dans la boucle, elle est anonyme).
  2. for _ in range(5):

  3. Faire quelque chose qui dépend de la valeur de la variable de boucle : dans ce cas, on donne un vrai nom à notre variable de boucle qui prendra des valeurs différentes à chaque tour de boucle.
  4. for k in range(5):

2B - Valeurs successives de la variable de boucle

for k in range(5):

Dans cette déclaration, la variable de boucle k commence à 0 et va être incrémenter de 1 à chaque tour de boucle.

k va prendre les valeurs 0 puis 1 puis 2 puis 3 puis 4. Elle n'ira pas jusqu'à 5.

Attention

  • 5 correspond au nombre de tours de boucle
  • mais la valeur finale de k n'est pas 5 mais 4.

2C - Déroulé d'une boucle avec variable de boucle

1 2 3 4 5 6 7
print("Hors boucle") for k in range(3): print("Action de boucle") print(k) print("Hors boucle")

Déroulé du programme :

  • L1
  • Bloc (L3-L4-L5) avec k à 0
  • Bloc (L3-L4-L5) avec k à 1
  • Bloc (L3-L4-L5) avec k à 2
  • L7

2D - Boucle bornée

On nomme les boucles POUR (ou FOR) des boucles bornées car on peut connaître à l'avance le nombre de fois où nous allons faire la boucle.

3 - Sémantique

Visualisation de range sous forme d'un tableau

L'évaluation de range(5) n'est un tableau mais on peut représenter la réponse sous forme d'un tableau à l'aide de la fonction native list().

>>> list(range(5)) [0, 1, 2, 3, 4]

Cela va nous permettre de donner du sens à cette syntaxe.

Sémantique de for k in range(5)

Vous avez compris que for k in range(5) permet de réaliser 5 tours de boucle, avec k qui va varier progressivement de 0 à 4.

On doit comprendre for k in range(5) de cette façon :

"Pour chaque valeur de k parmi [0, 1, 2, 3, 4], réaliser les actions indentées ci-dessous".

4 - Description plus complète de range()

Un seul argument envoyé : valeur "presque finale"

Lorsqu'on utilise range(10), l'interpréteur Python comprendra :

  • qu'on veut commencer à 0,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +1 à chaque tour de boucle.

Visualisons cela dans la console. Attention, il faudra appuyer deux fois sur ENTREE (représentée ici par ) pour valider la boucle dans la console.

>>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for k in range(10): print(k) 0 1 2 3 4 5 6 7 8 9

Deux arguments envoyés : valeur initiale, valeur "presque finale"

Lorsqu'on utilise range(3, 10), l'interpréteur Python comprendra :

  • qu'on veut commencer à 3,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +1 à chaque tour de boucle.

Visualisons cela dans la console.

>>> list(range(3, 10)) [3, 4, 5, 6, 7, 8, 9] >>> for k in range(3, 10): print(k) 3 4 5 6 7 8 9

Trois arguments envoyés : valeur initiale, valeur "presque finale", pas

Lorsqu'on utilise range(3, 10, 2), l'interpréteur Python comprendra :

  • qu'on veut commencer à 3,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +2 à chaque tour de boucle (on dira que le pas est de +2).

Visualisons cela dans la console.

>>> list(range(3, 10, 2)) [3, 5, 7, 9] >>> for k in range(3, 10, 2): print(k) 3 5 7 9

On peut d'ailleurs donner un pas négatif. Ca complique la compréhension de la vraie valeur finale : si la valeur finale est 1 en décroissant, la dernière valeur disponible est donc... 2.

>>> list(range(10, 1, -3)) [10, 7, 4] >>> for k in range(10, 1, -2): print(k) 10 7 4
5 - Boucle et concaténations successives

Nous voudrions créer une chaîne de caractères contentant "0 1 2 3 4 5 6 ... 1000" jusqu'à un entier final au choix (1000 sur l'exemple).

Nous allons créer la chaîne de caractères par concaténations successives, en écrasant la version précédente par la nouvelle version.

La signature de la concaténation de strings est str + str -> str.

Cela reviendrait à faire ceci à la main (et jusqu'à 1000, ça risque d'être long à taper...) :

1 2 3 4 5 .. 1002
chaine = "" chaine = chaine + str(0) + " " chaine = chaine + str(1) + " " chaine = chaine + str(2) + " " chaine = chaine + str(3) + " " ... chaine = chaine + str(1000) + " "

Plutôt que de tout faire à la main, utilisons une boucle dont la variable de boucle se nommerait nombre.

1 2 3
chaine = "" for nombre in range(1001): chaine = chaine + str(nombre) + " "

Attention à la phase d'initialisation de la ligne 1. Elle est très importante et nous allons la retrouver très souvent cette année.

6 - Boucle et additions successives

Nous voudrions faire la somme de plusieurs nombres 0 + 1 + 2 + 3 + 4 + 5 + 6 ... + 1000 jusqu'à un entier final au choix (1001 sur l'exemple).

Nous allons calculer la somme par additions successives, en écrasant la version précédente par la nouvelle version.

La signature de l'addition d'entiers' est int + int -> int.

Cela reviendrait à faire ceci à la main (et jusqu'à 1000, ça risque d'être long à taper...) :

1 2 3 4 5 .. 1001
somme = 0 somme = somme + 1 somme = somme + 2 somme = somme + 3 somme = somme + 4 ... somme = somme + 1000

Plutôt que de tout faire à la main, utilisons une boucle dont la variable de boucle se nommerait nombre.

1 2 3
somme = 0 for nombre in range(1, 1001): somme = somme + nombre

Attention à la phase d'initialisation de la ligne 1. Elle est très importante et nous allons la retrouver très souvent cette année.

7 - Affichage des éléments d'un tableau
1 2 3
t = [10, 20, 30] for i in range(len(t)): # Pour chaque indice i possible du tableau t print(t[i ]) # Affiche la case i du tableau t
10 20 30
1 2 3 4
t = [10, -20, 30] for i in range(len(t)): # Pour chaque indice i possible du tableau t for t[i ] > 0: # Si la case i du tableau t contient une valeur positive print(t[i ]) # Affiche la case i du tableau t
10 20 30

2 - Boucle bornée POUR / FOR

01° Placer le code suivant en mémoire : il affiche le message "C'est parti !" puis 5 fois le message "Et un tour de boucle" sur la console. Une fois la boucle terminée, il affiche "Go !".

Questions

1 2 3 4 5 6
print("C'est parti !") for _ in range(5): print("Et un tour de boucle") print("Fini !")
>>> %Run prog_boucle.py C'est parti ! Et un tour de boucle Et un tour de boucle Et un tour de boucle Et un tour de boucle Et un tour de boucle Fini !

Question

  1. Lancer le programme pour vérifier qu'il fonctionne.
  2. Que trouve-t-on à la fin de la déclaration de la boucle for (et qu'on trouve aussi à la fin d'une déclaration de fonction) ?
  3. Comment indique-t-on à l'interpréteur Python que la ligne 4 fait partie des choses à faire en boucle, et que la ligne 6 sera à faire après avoir fait entièrement la boucle ?
  4. Modifier le programme pour qu'il vous affiche 200 fois "Et un tour de boucle".

...CORRECTION...

  1. Le programme fonctionne.
  2. Comme pour les déclarations de fonction, la SYNTAXE impose la présence du symbole :.
  3. Comme dans les fonctions, c'est la tabulation (ou 4 espacesà qui indique à l'interpréteur que le bloc d'instructions fait partie de la boucle, ou pas. La ligne 6 est ainsi réalisée après avoir fait la boucle de multiple fois, puisqu'elle n'est pas tabulée.
  4. Il suffit de noter 200 à la place de 5.

02 ✔° Placer maintenant le programme dans Python Tutor et visualiser l'exécution progressive avec une boucle qui sera réalisé 10 fois (200 fois, ça risque d'être un peu long).

03 ✔° Placer le code suivant en mémoire : il permet de tracer un triangle en faisant appel à la fonction triangle().

Lancer le code pour visualiser que vous avez bien créé un triangle.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
# Partie Importation import turtle as trt # Partie déclaration des fonctions d'interface def triangle(feutre:trt.Turtle, distance:int, angle:int) -> None: '''Fait avancer le crayon de la distance, tourne de l'angle donné. Trois fois.''' feutre.forward(distance) feutre.left(angle) feutre.forward(distance) feutre.left(angle) feutre.forward(distance) feutre.left(angle) # Instructions du programme principal stylo = trt.Turtle() triangle(stylo, 100, 120)

04 ✔° Replacer la fonction triangle() par cette version qui utilise une boucle POUR / FOR. Tester pour visualiser qu'on continue bien à obtenir un triange.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
# Partie Importation import turtle as trt # Partie déclaration des fonctions d'interface def triangle(feutre:trt.Turtle, distance:int, angle:int) -> None: '''Fait avancer le crayon de la distance, tourne de l'angle donné. Trois fois.''' for _ in range(3): feutre.forward(distance) feutre.left(angle) # Instructions du programme principal stylo = trt.Turtle() triangle(stylo, 100, 120)

Vous avez dû comprendre le principe : le mot-clé for et in provoquent ensemble l'apparition d'une boucle : on réalise les lignes 11 et 12 trois fois à cause, visiblement, de la présence de range(3).

05° Si on utilise cette fonction, combien de fois va-t-on faire d'instructions "avance" et combien va-t-on faire d'instructions "tourne à gauche" ? Pour répondre, il faut se demander quelles sont les lignes qui appartiennent à la boucle POUR et quelles sont les lignes qui n'en font pas partie.

1 2 3 4 5 6 7
def exo(feutre, distance, angle): '''Que fait cette fonction ?''' for _ in range(3): feutre.forward(distance) feutre.left(angle) feutre.forward(distance) feutre.left(angle)

...CORRECTION...

Lignes 4 et 5 appartiennent à la boucle : on réalise donc trois fois l'action "avance" et "tourne".

Ensuite, on sort de la boucle.

On réalise donc les lignes 6 et 7 et donc "avance" et "tourne" une fois de plus.

En tout, on réalise donc 4 "avance" et 4 "tourne".

C'est l'indentation vers la droite qui permet à Python de comprendre les actions que vous voulez réaliser en boucle. Il faut donc placer une tabulation ou 4 espaces de suite pour savoir qu’elles sont les instructions rattachées au bloc. De plus, on remarquera qu’on met un double point [ : ] à la fin de la déclaration de la boucle for. Sans ce symbole, vous déclenchez une erreur. Ce double point permet de dire à l'interpréteur que la déclaration est finie : il peut maintenant exécuter en boucle.

Dans Thonny ou tout autre éditeur spécialisé dans Python, la tabulation est équivalente à 4 espaces. Attention par contre aux éditeurs multi-langages. La tabulation est parfois de 2 ou 3 espaces. Dans ce cas, votre code ne sera pas compris par l'interpréteur Python. Dans ce cas de figure, préférez les 4 espaces ou configurez votre éditeur pour forcer une tabulation équivalente à 4 espaces.

06 ✔° Observer la fonction suivante sans utiliser l'animation : combien de fois va-t-on réaliser la boucle ? Combien de fois va-t-on réaliser l'instruction "avance" ? Combien de fois va-t-on réaliser l'instruction "tourne à gauche" ?

Tester l'animation suivante pour être certain d'avoir compris le déroulé :

1 2 3 4 5 6 7
def exo(feutre, distance, angle): '''Que fait cette fonction ?''' feutre.forward(distance) for _ in range(5): feutre.forward(distance) feutre.left(angle) feutre.forward(distance)

CLIQUEZ ICI POUR VOIR LE DEROULEMENT SEQUENTIEL

...CORRECTION...

On voit range(5) : la boucle va être réalisée 5 fois.

On va donc "avancer"

  • 1 fois avant la boucle,
  • 5 fois avec les boucles et
  • une fois après la boucle

Soit 7 fois "avance" au total.

Pour l'action "tourne", on ne la réalise qu'une fois par tour de boucle. Il y a donc 5 "tourne" au total.

1 - Boucle POUR basique : réaliser plusieurs fois la même action

Pour réaliser plusieurs fois la même série d'actions, il suffit d'utiliser une boucle bornée POUR, qu'on déclare à l'aide du mot-clé for en Python.

1 2 3 4 5 6 7
print("Hors boucle") for _ in range(5): print("Action de boucle 1") print("Action de boucle 2") print("Hors boucle")

Déroulé du programme :

  • L1
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • Bloc (L3-L4-L5)
  • L7

On retrouve le même principe qu'avec les déclarations de fonction :

  1. Présence d'un point double ":" à la fin de la ligne de déclaration.
  2. Indentation pour indiquer quelles instructions appartiennent au bloc de la boucle : lignes 4 et 5 ici.
  3. La fin de la boucle est indiquée par le retour à la tabulation normale.

La syntaxe for _ in range(50) signale qu'on veut réaliser la boucle 50 fois.

Voyons comment tracer plein de formes différentes avec une même fonction en utilisant une variable de boucle.

  • Un triange équilatéral, c'est trois actions "avance et tourne de 120°", et on trouve facilement 120 en calculant 360 / 3.
  • Un carré, c'est quatre actions "avance et tourne de 90°", et on trouve facilement 90 en calculant 360 / 4.
  • ...

07° Compléter la fonction polygone() pour qu'elle réalise cela :

  • Calculer l'angle en faisant la division euclidienne de 360 par le nombre de côtés nb voulus : angle = 360 // nb
  • Réaliser une boucle POUR où on fait nb de fois la même chose :
    • Avancer de la longueur longueur
    • Tourner de l'angle angle

La documentation est fournie en mode multiligne.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# Partie Importation import turtle as trt # Partie déclaration des fonctions def polygone(feutre, nb, longueur): '''Crée un polygone à nb cotés, longueur étant la longueur de chaque côté :: param feutre(trt.Turtle) :: un objet-Turtle :: param nb(int) :: le nombre de côtés, strictement supérieur à 2 :: param longueur(int) :: la longueur de chaque côté en pixels. Entier positif. :: return(None) :: ne renvoie rien, trace uniquement la forme ''' pass # Instructions du programme principal stylo = trt.Turtle() polygone(stylo, 6, 100)

Vous devriez obtenir ceci après l'appel fourni sur la dernière ligne du programme :

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
# Partie Importation import turtle as trt # Partie déclaration des fonctions d'interface def polygone(feutre, nb, longueur): '''Crée un polygone à nb cotés, longueur étant la longueur de chaque côté :: param feutre(trt.Turtle) :: un objet-Turtle :: param nb(int) :: le nombre de côtés, strictement supérieur à 2 :: param longueur(int) :: la longueur de chaque côté en pixels. Entier positif. :: return(None) :: ne renvoie rien, trace uniquement la forme ''' angle = 360 // nb for _ in range(nb): feutre.forward(longueur) feutre.left(angle) # Instructions du programme principal stylo = trt.Turtle() polygone(stylo, 6, 100)

On peut maintenant s'amuser et réaliser plein de formes différentes. Imaginons qu'on fasse un appel du type polygone(stylo, 10, 50), il devrait provoquer cela :

Ou tracer un triangle avec un appel du type polygone(stylo, 3, 150), il devrait provoquer cela :

Reste un point à voir : qu'est-ce que ce _ qui traîne dans la boucle ?

3 - Etude de la variable de boucle

En réalité, cette indication _ désigne une variable particulière qu'on nomme variable de boucle.

Lorsqu'on sait qu'on ne va pas l'utiliser mais juste réaliser la même action plusieurs fois, la convention Python est de la nommer "underscore", pour montrer que son nom n'a pas d'importance puisqu'on ne l'utilise pas.

Regardons maintenant ce que contient cette variable de boucle lors du déroulé de la boucle. Nous allons la renommer k, plutôt que de la rendre invisible avec _.

Commençons par une animation qui vous permettra de comprendre de quelle valeur elle part et sa valeur finale.

08-A° Tester l'animation suivante.

Questions

1 2 3 4 5 6 7
def exo(feutre, distance, angle): '''Que fait cette fonction ?''' feutre.forward(distance) for k in range(5): feutre.forward(distance) feutre.left(angle) feutre.forward(distance)

CLIQUEZ ICI POUR VOIR LE DEROULEMENT SEQUENTIEL

k :

  1. Que vaut la variable de boucle k lors du premier tour de boucle ?
  2. Que vaut la variable de boucle k lors du dernier tour de boucle ?
  3. Quelles sont les valeurs successives prises par la variable de boucle k ?
  4. Combien de valeurs successives (et de tous de boucle) k a-t-elle eu lors du déroulé de la boucle ?

...CORRECTION...

  1. La variable de boucle k commence à 0 lors du premier tour de boucle.
  2. La variable de boucle k finit à 4 lors du dernier tour de boucle.
  3. La variable de boucle k a donc pris les valeurs successives 0 puis 1, puis 2, puis 3 et finalement 4/
  4. Il y a donc eu 5 valeurs différentes et donc 5 tours de boucle.

08-B° Regarder le programme ci-dessous puis répondre aux questions.

  1. Quelles vont être les valeurs successives prises par la variable de boucle k ?
  2. Combien de cas différents en tout ?
  3. Ecrire le programme équivalent sans boucle qui permettrait d'obtenir le même affichage.
1 2
for k in range(10): print(k)

Si vous n'êtes pas sûr de vous, Python Tutor est votre ami.

...CORRECTION...

La variable de boucle k commence à 0, puis prend la valeur 1, puis prend la valeur 2... jusqu'à arriver à 9.

ATTENTION : on ne va pas jusqu'à 10, on s'arrête juste avant :!

Les différentes valeurs sont : 0 1 2 3 4 5 6 7 8 9

Il y a bien 10 valeurs différentes qui s'étalent de 0 à 9.

1 2 3 4 5 6 7 8 9 10
print(0) print(1) print(2) print(3) print(4) print(5) print(6) print(7) print(8) print(9)

Pour visualiser la valeur de la variable de boucle à l'aide de Turtle, nous pourrions réaliser une boucle où on avance d'une longueur variant avec la variable de boucle, avant de tourner comme avant.

09-A° Lancer le code ci-dessous.

Voici le résultat attendu :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# Partie Importation import turtle as trt # Partie déclaration des fonctions def visualiser(feutre): '''Permet de visualiser la valeur de la variable de boucle''' for k in range(5): feutre.pensize(1+k) feutre.forward(50 + k*50) feutre.left(90) # Instructions du programme principal stylo = trt.Turtle() stylo.speed(1) visualiser(stylo)

Questions après analyse de la fonction

  1. Que valent la largeur du trait et la longueur du trait lors du premier tour de boucle (lorsque k vaut 0)  ?
  2. Que vaut la largeur du trait et la longueur du trait lors du deuxième tour de boucle (lorsque k vaut 1)  ?
  3. Quelle va être la valeur finale de la variable de boucle k ?

...CORRECTION...

  1. Lors du premier tour de boucle, k vaut 0.
    • Ligne 11 : on voit que la largeur du trait sera 1 + k, donc 1.
    • Ligne 12 : on voit qu'on avance de 50 + k*50, donc 50.
  2. Lors du deuxième tour de boucle, k vaut 1.
    • Ligne 11 : on voit que la largeur du trait sera 1 + k, donc 2.
    • Ligne 12 : on voit qu'on avance de 50 + k*50, donc 50 + 2*50 ce qui donne 150.
  3. Lors du dernier tour de boucle, k vaut 4.
    • Ligne 11 : on voit que la largeur du trait sera 1 + k, donc 5.
    • Ligne 12 : on voit qu'on avance de 50 + k*50, donc 50 + 4*50 ce qui donne 250.

09-B° On également utiliser la variable de boucle pour jouer le rôle d'indice dans un tableau. On reprend le même programme en rajoutant simplement cette fois une tableau de couleurs et une modification du crayon à chaque tour de boucle : on va lire une case du tableau en fonction de la valeur de la variable de boucle x.

Vous devriez obtenir ceci maintenant (sans les valeurs de x, je les ai rajouté pour identifier facilement les étapes):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# Partie Importation import turtle as trt # Partie déclaration des fonctions def visualiser(feutre): '''Permet de visualiser la valeur de la variable de boucle''' couleurs = ["grey", "red", "blue", "green", "purple"] for x in range(5): feutre.color(couleurs[x]) feutre.pensize(1+x) feutre.forward(50+x*50) feutre.left(90) # Instructions du programme principal stylo = trt.Turtle() stylo.speed(1) visualiser(stylo)

Question

Expliquer pourquoi le crayon est gris au premier tour de boucle puis rouge au deuxième tour de tour. Un rappel est fourni ci-dessous si vous en avez besoin

Rappel sur la lecture des cases d'un tableau (le type construit list de Python)

>>> t = ["Alice", "Bob"] >>> t[0] 'Alice' >>> t[1] 'Bob' >>> len(t) 2

...CORRECTION...

Lors du premier tour de boucle, x vaut 0.

C'est donc comme si nous avions tapé feutre.color(couleurs[0])

Si nous allons voir le contenu de cette case du tableau, nous voyons qu'elle contient la couleur "grey".

Après évaluation, on a donc feutre.color("grey")

Lors du deuxième tour de boucle, x vaut 1.

C'est donc comme si nous avions tapé feutre.color(couleurs[1])

Si nous allons voir le contenu de cette case du tableau, nous voyons qu'elle contient la couleur "blue".

Après évaluation, on a donc feutre.color("blue")

✌ 09-C° Regardons maintenant comment parvenir à rajouter le texte au dessus du trait à chaque début de tour de boucle.

Pour cela, il faut utiliser la méthode write() sur le stylo (voir ligne 12).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# Partie Importation import turtle as trt # Partie déclaration des fonctions def visualiser(feutre): '''Permet de visualiser la valeur de la variable de boucle''' couleurs = ["grey","red", "blue", "green", "purple"] for x in range(5): feutre.color(couleurs[x]) feutre.write(f"x = {x}") feutre.pensize(1+x) feutre.forward(50+x*50) feutre.left(90) # Instructions du programme principal stylo = trt.Turtle() stylo.speed(1) visualiser(stylo)

Vous devriez maintenant obtenir la même image que celle de la sous-question précédente.

Nouveauté : le f-String

On notera qu'on utilise ici un f-String : c'est string dont les guillemets d'ouverture sont précédes d'un f. A l'intérieur du string, on peut alors placer accolades {} qui vont jouer un rôle particulier : l'interpéteur Python évalue l'expression fournie entre les accolades et place la valeur obtenue à cet endroit dans le string.

Exemple :

>>> a = "Alice" >>> b = "Bob" >>> c = f"Bonjour à {a} et à {b}" >>> c 'Bonjour à Alice et Bob' >>> n1 = 20 >>> n2 = 20 >>> f"La moyenne est de {n1} et {n2} donne {(n1 + n2) / 2}" 'La moyenne de 20 et 15 donne 17.5'

Question

Après avoir tapé les exemples précédents dans la console (et les avoir réellement compris), modifier la fonction pour qu'elle provoque un affichage : "Sur cette étape, x vaut 0", "Sur cette étape, x vaut 1"...

2 - Boucle et variable de boucle

2A - Variable de boucle

On peut utiliser une boucle POUR de façon à

  1. Faire plusieurs fois la même chose (voir 1). On donne alors souvent le nom _ à la variable de boucle (pour indiquer qu'elle ne sert à rien de particulier dans la boucle, elle est anonyme).
  2. for _ in range(5):

  3. Faire quelque chose qui dépend de la valeur de la variable de boucle : dans ce cas, on donne un vrai nom à notre variable de boucle qui prendra des valeurs différentes à chaque tour de boucle.
  4. for k in range(5):

2B - Valeurs successives de la variable de boucle

for k in range(5):

Dans cette déclaration, la variable de boucle k commence à 0 et va être incrémenter de 1 à chaque tour de boucle.

k va prendre les valeurs 0 puis 1 puis 2 puis 3 puis 4. Elle n'ira pas jusqu'à 5.

Attention

  • 5 correspond au nombre de tours de boucle
  • mais la valeur finale de k n'est pas 5 mais 4.

2C - Déroulé d'une boucle avec variable de boucle

1 2 3 4 5 6 7
print("Hors boucle") for k in range(3): print("Action de boucle") print(k) print("Hors boucle")

Déroulé du programme :

  • L1
  • Bloc (L3-L4-L5) avec k à 0
  • Bloc (L3-L4-L5) avec k à 1
  • Bloc (L3-L4-L5) avec k à 2
  • L7

2D - Boucle bornée

On nomme les boucles POUR (ou FOR) des boucles bornées car on peut connaître à l'avance le nombre de fois où nous allons faire la boucle.

4 - Description plus complète de range

3 - Sémantique

Visualisation de range sous forme d'un tableau

L'évaluation de range(5) n'est un tableau mais on peut représenter la réponse sous forme d'un tableau à l'aide de la fonction native list().

>>> list(range(5)) [0, 1, 2, 3, 4]

Cela va nous permettre de donner du sens à cette syntaxe.

Sémantique de for k in range(5)

Vous avez compris que for k in range(5) permet de réaliser 5 tours de boucle, avec k qui va varier progressivement de 0 à 4.

On doit comprendre for k in range(5) de cette façon :

"Pour chaque valeur de k parmi [0, 1, 2, 3, 4], réaliser les actions indentées ci-dessous".

Nous allons voir qu'on peut en réalité configurer assez facilement les valeurs successives à l'aide de range() :

  • on peut commencer à une autre valeur que 0,
  • on peut compter de 4 en 4,
  • on peut compter dans le sens décroissant.
4 - Description plus complète de range()

Un seul argument envoyé : valeur "presque finale"

Lorsqu'on utilise range(10), l'interpréteur Python comprendra :

  • qu'on veut commencer à 0,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +1 à chaque tour de boucle.

Visualisons cela dans la console. Attention, il faudra appuyer deux fois sur ENTREE (représentée ici par ) pour valider la boucle dans la console.

>>> list(range(10)) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for k in range(10): print(k) 0 1 2 3 4 5 6 7 8 9

Deux arguments envoyés : valeur initiale, valeur "presque finale"

Lorsqu'on utilise range(3, 10), l'interpréteur Python comprendra :

  • qu'on veut commencer à 3,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +1 à chaque tour de boucle.

Visualisons cela dans la console.

>>> list(range(3, 10)) [3, 4, 5, 6, 7, 8, 9] >>> for k in range(3, 10): print(k) 3 4 5 6 7 8 9

Trois arguments envoyés : valeur initiale, valeur "presque finale", pas

Lorsqu'on utilise range(3, 10, 2), l'interpréteur Python comprendra :

  • qu'on veut commencer à 3,
  • que la valeur "presque" finale (c'est à dire exclue) est 10 et
  • qu'on incrémentera la variable de boucle de +2 à chaque tour de boucle (on dira que le pas est de +2).

Visualisons cela dans la console.

>>> list(range(3, 10, 2)) [3, 5, 7, 9] >>> for k in range(3, 10, 2): print(k) 3 5 7 9

On peut d'ailleurs donner un pas négatif. Ca complique la compréhension de la vraie valeur finale : si la valeur finale est 1 en décroissant, la dernière valeur disponible est donc... 2.

>>> list(range(10, 1, -3)) [10, 7, 4] >>> for k in range(10, 1, -2): print(k) 10 7 4

✌ 10° Expliquer les valeurs successives que vont prendre les variables de boucle a, b et c dans les cas suivants :

>>> for a in range(100): print(a) ??? >>> for b in range(80, 101, 10): print(b) ??? >>> for c in range(100, 49, -10): print(c) ???
5 - Boucle et concaténations successives

Nous voudrions créer une chaîne de caractères contentant "0 1 2 3 4 5 6 ... 1000" jusqu'à un entier final au choix (1000 sur l'exemple).

Nous allons créer la chaîne de caractères par concaténations successives, en écrasant la version précédente par la nouvelle version.

La signature de la concaténation de strings est str + str -> str.

Cela reviendrait à faire ceci à la main (et jusqu'à 1000, ça risque d'être long à taper...) :

1 2 3 4 5 .. 1002
chaine = "" chaine = chaine + str(0) + " " chaine = chaine + str(1) + " " chaine = chaine + str(2) + " " chaine = chaine + str(3) + " " ... chaine = chaine + str(1000) + " "

Plutôt que de tout faire à la main, utilisons une boucle dont la variable de boucle se nommerait nombre.

1 2 3
chaine = "" for nombre in range(1001): chaine = chaine + str(nombre) + " "

Attention à la phase d'initialisation de la ligne 1. Elle est très importante et nous allons la retrouver très souvent cette année.

11 ✔° Lancer ce programme et vérifier que la chaine obtenue est correcte :

1 2 3
chaine = "" for nombre in range(1001): chaine = chaine + str(nombre) + " "
>>> chaine '0 1 2 3 4 5 6 7 8 9 ... 1000'

12° Répondre aux trois questions suivantes :

Question A  dans ce programme de concaténations successives, que contient chaine avant le premier tour de boucle ? Comment se nomme la phase correspondant à la ligne 1 ?

1 2 3
chaine = "" for nombre in range(1001): chaine = chaine + str(nombre) + " "

Question B  expliquer l'erreur obtenue si on ne place pas la ligne 1 ?

1 2 3
for nombre in range(1001): chaine = chaine + str(nombre) + " "
chaine = chaine + str(nombre) + " " NameError: name 'chaine' is not defined

Question C  pourquoi un humain parviendrait-il à exécuter cela si on lui donner des instructions en oubliant la ligne 1 ?

...CORRECTION...

Question A

La chaine contient une première valeur d'initialisation.

Question B

On voit que l'initialisation est indispensable car, sinon, python ne serait pas en capacité d'évaluer chaine = chaine + .... Puisqu'il commence l'évaluation à droite, il ne connaît pas chaine et ne peut donc pas l'évaluer.

Question C

L'humain a un avantage énorme sur la machine : il peut remplir les trous avec son intuition et sa capacité d'analyse. Il est libre d'interpréter à sa guise et de donner du sens à l'instruction : il manque une première valeur ? Ok, prenons un caractère vide. La machine ne fait qu'exécuter, sans réflexion ni analyse. C'est juste une machine.

13-A° Fournir un programme permettant d'obtenir une chaîne où on compte de 10 à 40 (inclus), de deux en deux. Attention à la borne finale. On veut aller vraiment jusqu'à 40.

On veut donc obtenir ceci :

>>> chaine '10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 '

...CORRECTION...

1 2 3
chaine = "" for nombre in range(10, 41, 2): chaine = chaine + str(nombre) + " "

13-B° Fournir un code permettant de compter cette fois de 100 à 10 (inclus) en diminuant de cinq à chaque tour de boucle. Attention à la borne finale

On veut donc obtenir ceci :

>>> chaine '100 95 90 85 80 75 70 65 60 55 50 45 40 35 30 25 20 15 10 '

...CORRECTION...

1 2 3
chaine = "" for nombre in range(100, 9, -5): chaine = chaine + str(nombre) + " "

5 - Exos

✎ 14° Créer une fonction punition() qui attend deux paramètres :

1 2 3 4 5 6 7 8 9
def punition(ligne_a_copier, nombre_de_fois): '''Réalise la punition à la place de l'élève :: param ligne_a_copie(str) :: la ligne qu'on va devoir recopier :: param nombre_de_fois(int) :: le nombre de lignes à faire au total :: return (None) :: ne renvoie rien, "procédure Python". ''' pass

Votre fonction devra afficher (afficher donc print()) dans la console la phrase autant de fois que demandé.

Exemple d'utilisation :

>>> punition("Je ne dois pas sortir mon téléphone portable en classe", 3) Je ne dois pas sortir mon téléphone portable en classe Je ne dois pas sortir mon téléphone portable en classe Je ne dois pas sortir mon téléphone portable en classe

15° Combien va-t-on dessiner de cercles ?

1 2 3
for a in range(5): dessiner_un_cercle() dessiner_un_cercle() dessiner_un_cercle() dessiner_un_cercle()

Deuxième version en anonymisant la variable de boucle dans la mesure où elle n'intervient pas dans les actions de la boucle :

1 2 3
for _ in range(5): dessiner_un_cercle() dessiner_un_cercle() dessiner_un_cercle() dessiner_un_cercle()

...CORRECTION 1-2...

Nous allons faire 5 tours de boucles en L1 avec une variable de boucle a qui prendra les valeurs 0, 1, 2, 3 et 4 mais dont on utilisera pas la valeur pendant la boucle.

Et lors de chacun des tours de boucle, on dessine 4 cercles.

Il va donc y avoir 5 * 4 = 20 cercles.

16° Combien va-t-on dessiner de cercles ?

1 2 3
for a in range(5): for b in range(4): dessiner_un_cercle()

...CORRECTION 1-2...

Encore 20.

Pourquoi ?

A chaque fois qu'on réalise entiérement la boucle présente en L2 (qu'on nommera Boucle 2), on dessine 4 cercles.

Or, on réalise la boucle présente en L1 5 fois. Or pendant chaque tour de la boucle 1, on exécute 4 fois la boucle 2. 5*4 = 20.

Description au cas par cas :

  • D'abord a vaut 0 et
    • Une exécution de la ligne 3 avec b valant 0 : 1 cercle.
    • Une exécution de la ligne 3 avec b valant 1 : 2 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 3 cercles.
    • Une exécution de la ligne 3 avec b valant 3 : 4 cercles.
    • Fin de la boucle 2
  • Puis a vaut 1 et
    • Une exécution de la ligne 3 avec b valant 0 : 5 cercles.
    • Une exécution de la ligne 3 avec b valant 1 : 6 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 7 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 8 cercles.
    • Fin de la boucle 2
  • Puis a vaut 2 et
    • Une exécution de la ligne 3 avec b valant 0 : 9 cercles.
    • Une exécution de la ligne 3 avec b valant 1 : 10 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 11 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 12 cercles.
    • Fin de la boucle 2
  • Puis a vaut 3 et
    • Une exécution de la ligne 3 avec b valant 0 : 13 cercles.
    • Une exécution de la ligne 3 avec b valant 1 : 14 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 15 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 16 cercles.
    • Fin de la boucle 2
  • Finalement a vaut 4 et
    • Une exécution de la ligne 3 avec b valant 0 : 17 cercles.
    • Une exécution de la ligne 3 avec b valant 1 : 18 cercles.
    • Une exécution de la ligne 3 avec b valant 2 : 19 cercles.
    • Une exécution de la ligne 3 avec b valant 3 : 20 cercles.
    • Fin de la boucle 2
  • Fin de la boucle 1

Tout cela peut se résumer à 5 tours de boucle 1 comportant à chaque fois 4 tours de boucle 2, soit 5 * 4 = 20 cercles dessinés.

17° Que va afficher ce programme ? Expliquer l'ordre de l'affichage obtenu.

1 2 3
for a in range(2, 9, 3): for b in range(10, 101, 20): print(f"a = {a} et b = {b}")

...CORRECTION 1-2...

La variable de boucle a va prendre les valeurs 2, 5, 8.

Lors du premier tour de boucle, la valeur de a est donc 2.

La variable de boucle b va prendre les valeurs 10, 30, 50, 70, 90. Soit 5 tours de boucles différents.

On va donc obtenir ceci lors du premier tour de boucle sur a :

a = 2 et b = 10 a = 2 et b = 30 a = 2 et b = 50 a = 2 et b = 70 a = 2 et b = 90

Ensuite, on va revenir sur un nouveau tour de boucle pour a qui devient 5.

a = 5 et b = 10 a = 5 et b = 30 a = 5 et b = 50 a = 5 et b = 70 a = 5 et b = 90

Enfin, on fait le dernier tour de boucle pour a qui devient 8.

a = 8 et b = 10 a = 8 et b = 30 a = 8 et b = 50 a = 8 et b = 70 a = 8 et b = 90

✎ 18° Expliquer clairement pourquoi le programme suivant crée exactement 16 cercles. Pour cela, il "suffit" de savoir répondre aux question suivantes (si vous n'y arrivez pas seul, Python Tutor n'est pas votre ami car il n'intègre pas Turtle !) :

  1. Combien de fois cercles() (avec un s) va être appelée pendant l'exécution de la fonction dessin() ?
    • Autrement dit : combien de valeurs différentes va prendre la variable de boucle angle de la ligne 18 ?
  2. Lors des appels à cercles(), comprendre ce que vont recevoir les paramètres rmax, rmin et pas.
  3. Lors de chacun des appels à cercles() (avec un s) combien d'appels à cercle() (sans s) ?
    • Autrement dit : combien de valeurs différentes va prendre la variable de boucle rayon de la ligne 13 ?

Voici le programme utilisé pour réaliser ce dessin.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
import turtle as trt def cercle(rayon, angle): '''Fonction qui trace UN cercle.''' feutre = trt.Turtle() feutre.color('red') feutre.pensize(5) feutre.setheading(angle) feutre.circle(rayon, 360) def cercles(rmin, rmax, pas, angle): '''Fonction qui trace DES cercles en utilisant... cercle()''' for rayon in range(rmin, rmax, pas): cercle(rayon, angle) def dessin(): '''Fonction qui trace un dessin en utilisant cercles()''' for angle in range(0, 360, 90): cercles(50, 150, 25, angle) dessin()

Pour info (ça ne sert à rien pour résoudre la question), la méthode setheading() permet de forcer la tortue à regarder dans une direction précise (qu'on fournit sous forme d'un angle : 0° veut dire de regarder vers la droite, 180° vers la gauche...).

✎ 19-A° On veut réaliser une fonction somme() qui renvoie la somme des n premiers entiers.

Par exemple, somme(4) doit renvoyer la somme de 0+1+2+3+4, soit 10.

Nous allons donc faire cela en boucle.

On crée une variable de stockage qu'on nommera s.

A chaque étape, on va donc rajouter la valeur de la valeur de boucle à la variable s et remettre le résultat dans la variable s.

On aura ainsi :

Initialisation : s = 0

Premier tour de boucle : s = s + 0, soit s = 0

Deuxième tour de boucle : s = s + 1, soit s = 1

Troisième tour de boucle : s = s + 2, soit s = 3

Quatrième tour de boucle : s = s + 3, soit s = 6

...

Compléter la fonction somme() pour qu'elle fonctionne correctement :

1 2 3 4 5 6
def somme(n:int): '''Renvoie la somme des entiers de 1 jusqu'à n INCLUS''' s = ... for x in range(..., ..., ...): s = s + ... return ...
>>> somme(3) 6 >>> somme(4) 10 >>> somme(5) 15 >>> somme(6) 21

Tant que la fonction ne renvoie pas cela, c'est que votre fonction ne fonctionne pas !

✌ 19-B° Vous décidez d'organiser une fête, payante.

Le premier arrivé doit payer un euro, le deuxième 2 euros, le troisième 3 euros...

Vous avez eu 600 clients avant que plus personne n'accepte de payer.

Quelle somme d'argent avez-vous récolté ?

✎ 20° Utiliser le programme ci-dessous. Visualiser le résultat puis expliquer pourquoi on voit cette succession de formes et de couleurs. Pas facile, facile. Beaucoup de notions en même temps vont être nécessaires pour comprendre ce programme.

1 2 3 4 5 6 7 8 9 10
import turtle as trt couleurs = ["gold", "white", "blue" ] crayon = trt.Turtle() crayon.speed(0) trt.bgcolor('black') for x in range(800): crayon.pencolor(couleurs[x % 3]) crayon.width(x//100 + 1) crayon.forward(x) crayon.left(59)
6 - Boucle et additions successives

Nous voudrions faire la somme de plusieurs nombres 0 + 1 + 2 + 3 + 4 + 5 + 6 ... + 1000 jusqu'à un entier final au choix (1001 sur l'exemple).

Nous allons calculer la somme par additions successives, en écrasant la version précédente par la nouvelle version.

La signature de l'addition d'entiers' est int + int -> int.

Cela reviendrait à faire ceci à la main (et jusqu'à 1000, ça risque d'être long à taper...) :

1 2 3 4 5 .. 1001
somme = 0 somme = somme + 1 somme = somme + 2 somme = somme + 3 somme = somme + 4 ... somme = somme + 1000

Plutôt que de tout faire à la main, utilisons une boucle dont la variable de boucle se nommerait nombre.

1 2 3
somme = 0 for nombre in range(1, 1001): somme = somme + nombre

Attention à la phase d'initialisation de la ligne 1. Elle est très importante et nous allons la retrouver très souvent cette année.

7 - Affichage des éléments d'un tableau

1 2 3
t = [10, 20, 30] for i in range(len(t)): # Pour chaque indice i possible du tableau t print(t[i ]) # Affiche la case i du tableau t
10 20 30
1 2 3 4
t = [10, -20, 30] for i in range(len(t)): # Pour chaque indice i possible du tableau t for t[i ] > 0: # Si la case i du tableau t contient une valeur positive print(t[i ]) # Affiche la case i du tableau t
10 20 30

6 - Mode DEBUG de Thonny

REMARQUE

Cette partie sera à faire ensemble : c'est un ensemble de manipulation. Ce n'est pas compliqué mais lire les manipulations à faire est plus difficile que de les faire directement.

Si vous n'utilisez pas Thonny, vous pouvez passer à la partie suivante.

Le logiciel Thonny possède une fonctionnalité que vous avez déjà rencontré  le mode PAS A PAS. Il permet d'exécuter du code ligne par ligne. Nous allons voir comment il fonctionne sur les boucles (et plus généralement les blocs d'instructions).

DEBUG 1° Placer ce code dans Thonny SANS LE LANCER. Ouvrir l'onglet VIEW-VARIABLES pour observer les variables.

1 2 3
chaine = "" for nombre in range(2, 10, 2): chaine = chaine + str(nombre) + " "

Pour lancer le mode DEBUG / PAS A PAS, il faut appyer sur le bouton "BUG" situé à DROITE de la flèche verte permettant juste de lancer le script.

Appuyer sur ce bouton et suivre les indications ci-dessous.

Vous devriez obtenir la première ligne en surbrillance : Thonny attend que vous validiez cette ligne. Pour l'instant, il n'a rien fait.

Pour lui demander d'exécuter cette ligne, il faut appuyer sur le bouton qui se trouve à droite du BUG et qui se nomme STEP OVER :

DEBUG 2° Appuyer sur le bouton STEP OVER.

On constate alors bien l'apparition d'une variable chaine ne contenant rien.

On voit que Thonny attend patiemment qu'on lui donne l'autorisation d'exécuter ce bloc en surbrillance.

Or, nous voulons voir comment s'exécute ce bloc pas à pas, nous ne voulons pas l'exécuter d'un coup. Pour cela, il va encore falloir appuyer sur un autre bouton : le bouton STEP INTO, qui permet de rentrer dans l'évaluation du bloc.

DEBUG 3° Appuyer sur le bouton STEP INTO.

On rentre bien dans le bloc et Thonny vous demande s'il peut commencer à évaluer l'ensemble des valeurs qu'il va devoir générer une à une :

DEBUG 4° Appuyer sur le bouton STEP OVER pour autoriser Thonny à exécuter cette évaluation (sans rentrer dans le détail de l'évaluation)

On obtient alors bien la première valeur de la suite, à savoir 2.

DEBUG 5° Appuyer encore sur le bouton STEP OVER pour autoriser Thonny à exécuter cette évaluation (sans rentrer dans le détail de l'évaluation)

On voit à droite qu'il a créé une variable nombre valant 2.

Il attend donc de pouvoir exécuter la ligne en surbrillance.

DEBUG 6° Valider chacune des instructions pour voir la création progressive de la chaîne de caractères.

Voici le résultat :

Lorsqu'on validera cette ligne, Python va donc concaténer '2 ' + '4' + ' ' qui sera évaluée à '2 4 ' et placée à nouveau dans la variable chaine. Résultat en image ci-dessous :

Lorsqu'on validera cette ligne, Python va donc concaténer '2 4 ' + '6' + ' ' qui sera évaluée à '2 4 6 ' et placée à nouveau dans la variable chaine. Résultat en image ci-dessous :

Nous arrivons ici à la dernière instruction puisque la variable de boucle ne pourra plus augmenter de 2. La chaîne de caractères va donc subir une dernière concaténation avant d'arriver à son état final.

Lorsqu'on validera cette ligne, Python va donc concaténer '2 4 6 ' + '8' + ' ' qui sera évaluée à '2 4 6 8 ' et placé à nouveau dans la variable chaine. Résultat en image ci-dessous :

Nous reviendrons régulièrement sur ce mode DEBUG. Dès qu'on change vous semble étrange, pensez à l'utiliser : cela vous permet de voir ce que Python fait VRAIMENT avec votre code.

7 - DEBUG avec Pythontutor

Vous pouvez également faire la même chose avec le site Pythontutor bien entendu.

DEBUG 7° Placer ce code sur le site Pythontutor. Il faut

  1. cliquer sur Start visualizing your code now,
  2. placer votre code.
  3. cliquer sur Visualize Execution
  4. avancer instruction par instruction avec Next
1 2 3
chaine = "" for nombre in range(2, 10, 2): chaine = chaine + str(nombre) + " "

Au final, vous arriverez bien entendu au même point qu'avec Thonny, à savoir ceci :

8 - FAQ

J'ai vu un code bizarre une variable... bizarre aussi. C'est quoi ?

Le code ressemble peut-être à ceci, avec une variable de boucle limité à un underscore :

1 2 3 4 5
def polygone(feutre, nbr, longueur): '''Crée un polygone à nbr cotés ayant chacun la longueur voulue.''' angle = 360 // nbr for _ in range(nbr): avance_et_tourne(feutre, longueur, angle)

C'est juste une notation qui permet en gros de dire : "La variable de boucle n'a aucune importance : on fait X fois la même chose"

Remplacez ce nom de variable de boucle par choucroute et ca marchera toujours aussi bien. Du coup, certains aiment bien mettre un underscore dans ce cas. Pourquoi pas ?

Voilà pour les boucles bornées qui permettent donc de faire plusieurs fois la même chose, ou presque puisqu'on peut utiliser la variable de boucle qui possède une valeur différente à chaque tour de boucle.

Avec ce style de boucle, on doit savoir à l'avance combien de fois on veut précisement réaliser l'action. Mais parfois, ce n'est pas possible. Imaginons qu'on veuille déplacer une balle à l'écran et la faire rebondir sur le coin de l'écran. Comment prévoir à l'avance lorsqu'il faudra la faire rebondir ? Et dans ce cas, on utilise un autre type de boucle : la boucle non bornée, ou while. Une boucle dont on ne connait pas forcément à l'avance le nombre de fois où l'exécution va se faire. C'est l'objet d'une autre activité.

Activité publiée le 01 11 2020
Dernière modification : 12 10 2022
Auteur : ows. h.