Itération#

L’itération est la capacité d’exécuter à plusieurs reprises un bloc d’instructions.

Vidéo: Instructions while et for#

Mise à jour d’une variable#

On parle de mise à jour de la variable lorsque la valeur de ré-affectation d’une variable dépend de son ancienne valeur. Par exemple :

# Création et affectation de la variable x (initialisation)
x = 0

# Mise à jour de la variable x
x = x + 1

Si on ajoute 1 à la valeur de la variable, on appelle cela une incrémentation. Si on enlève 1, c’est une décrémentation.

L’instruction while#

L’instruction while signifie tant que. Elle est suivie d’une condition. C’est une façon de répéter une instruction if. Voici un exemple de compte à rebours :

# Initialisation
n = 3

# Compte à rebours
while n > 0:
    print(n)
    n = n - 1
print("Partez !")
3
2
1
Partez !

La variable n est initialisée à 3. Lors de la première exécution de l’instruction while, n vaut 3 et donc la condition n > 0 est vraie. Le bloc d’instructions (indenté) est alors exécuté : on affiche 3 à l’écran, et n est incrémenté. C’est la première itération. Lors de la deuxième itération, n vaut 2. La condition est toujours vraie donc le bloc d’instructions est exécuté une deuxième fois. Idem pour la troisième itération où n vaut 1. Lors de la quatrième itération, n vaut 0 donc la condition est fausse : le bloc d’instructions n’est pas exécuté et on passe à la première instruction qui n’est pas indentée après le while.

Le flux d’exécution pour une instruction while est :

  1. Déterminer si la condition est vraie ou fausse ;

  2. Si elle est fausse, passer le bloc d’instructions (indenté) suivant l’instruction while, et poursuivre l’exécution à l’instruction suivante ;

  3. Si la condition est vraie, exécuter le bloc d’instructions, puis retourner à l’étape 1.

Ce type de flux est une boucle car l’étape 3 reboucle à l’étape 1. Le bloc d’instructions doit changer la valeur d’au moins une variable pour que la condition finisse par devenir fausse au bout d’un certain nombre d’itérations. Si ce n’est pas le cas, on aura alors une boucle infinie, car le bloc d’instructions sera répété à l’infini. Il faudra alors interrompre le programme d’une manière ou d’une autre.

Exercice#

Initialisez une variable appelée x à 40. Créer une boucle while qui, tant que x est supérieur à 1, divise x par 4. À la sortie de la boucle, afficher à l’écran la valeur de x.

Hide code cell source
# Initialisation
x = 40

# Boucle while
while x > 1:
    x = x / 4.0

# Afficher le résultat
print(x) 
0.625

L’instruction break#

Il arrive que nous voulions arrêter la boucle while à l’intérieur du bloc d’instructions, si une certaine condition est vraie. Dans ce cas on ne laisse pas la boucle aller jusqu’au bout. Pour cela on peut utiliser l’instruction break pour forcer à sortir de la boucle.

Reprenons l’exemple du compte à rebours :

# Initialisation
n = 5.8

# Compte à rebours
while n > 0:
    if n % 1 != 0:
        print("n doit être entier")
        break
    print(n)
    n = n - 1
n doit être entier

Dans cet exemple on vérifie si le compteur du compte à rebours est bien un entier, à l’intérieur de la boucle. Si ce n’est pas le cas, alors on n’exécute pas la boucle et on affiche un message d’erreur à l’utilisateur.

Exercice#

Reprendre l’exercice précédent. Dans la boucle, ajouter une condition qui vérifie que x est un nombre pair. Si ce n’est pas le cas, afficher le message d’erreur "x doit être pair" et sortir de la boucle.

Hide code cell source
# Initialisation
x = 40

# Boucle while
while x > 1:
    # Vérification que x est pair
    if x % 2 != 0:
        print("x doit être pair")
        break
    x = x / 4.0
x doit être pair

Bon usage

Bien que l’instruction break puisse être pratique, il est souvent recommandé de l’utiliser le moins possible. Cette instruction peut être la source d’erreurs difficiles à trouver. En effet, normalement, si on sort d’une boucle while, c’est parce que la condition n’est plus satisfaite ; et s’il y a plusieurs points où il est possible de sortir de la boucle while, il peut être (très) difficile de savoir quelle est la condition qui doit être vérifiée pour sortir, et donc de continuer à programmer. L’usage excessif de l’instruction break (ainsi que continue, ou le fameux goto qui n’existe pas en Python) est qualifié de programmation spaghetti.

Une meilleure solution de l’exercice précédent, sans break, est donc ceci :

# Initialisation
x = 40

# Initialisation d'une variable booléenne qui vaut True si x est pair
pair = x % 2 == 0
# Boucle while avec une unique condition de sortie
while x > 1 and pair:
    x = x / 4.0
    pair = x % 2 == 0
# Vérification que x est pair
if not pair:
    print("x doit être pair")
x doit être pair

L’instruction for#

L’instruction for est utilisée lorsque le nombre d’itérations est connu à l’avance. Voici par exemple une version du compte à rebours utilisant une boucle for :

n = 3
for i in range(n):
    print(n - i)
print("Partez !")
3
2
1
Partez !

L’instruction range() est un type de Python qui représente une séquence immuable de nombres. Il s’utilise de la façon suivante :

range(start, stop, step)

start, stop et step sont des entiers. La séquence créée contient alors des entiers dans l’intervalle semi-ouvert [start, stop[ (stop est exclu), avec un pas égal à step. Pour transformer l’objet de type range en objet de type list, on peut utiliser la fonction list() :

list(range(2, 14, 3))
[2, 5, 8, 11]

Exercice#

Créer une boucle for qui affiche les multiples de 4 compris entre 1 et 20 (inclus).

Hide code cell source
for i in range(1, 6):
    print(4 * i)
4
8
12
16
20
Hide code cell source
# Ou bien
for i in range(1, 21):
    if i % 4 == 0:
        print(i)
4
8
12
16
20
Hide code cell source
# Ou bien
for i in range(4, 21, 4):
    print(i)
4
8
12
16
20

Vidéo: Itération sur des objets#

Itérer sur une liste#

Une particularité de Python est de pouvoir itérer sur de nombreux objets composés. En particulier, il est possible d’itérer sur les éléments d’une liste :

# Création d'une liste
L = ['b', 2, True, 5.897]

# Itération sur les éléments de la liste
for x in L:
    print(x)
b
2
True
5.897

Il est possible d’accéder aussi à l’indice de l’élément avec la fonction enumerate() :

# Itération sur les indices et les éléments de la liste
for i, x in enumerate(L):
    print('indice', i, ':', x)
indice 0 : b
indice 1 : 2
indice 2 : True
indice 3 : 5.897

ou bien encore d’itérer sur une liste de listes :

# Création d'une liste de listes
taille_plantes = [["gentiane",  7.5 ], 
                  ["campanule", 5.8 ],
                  ["pensée",    11.4]]

# Iteration
for L in taille_plantes:
    print('taille', L[0], ':', L[1], 'cm')
taille gentiane : 7.5 cm
taille campanule : 5.8 cm
taille pensée : 11.4 cm

Exercice#

Créons la liste de listes donnant les superficie en \(\mathrm{m}^2\) des pièces d’une maison :

maison = [["cuisine", 18.0], 
          ["salon", 20.0], 
          ["chambre", 10.75], 
          ["salle de bains", 9.50]]

En utilisant une boucle for, afficher pour chaque pièce le numéro de la pièce (en commençant par 1), le nom de la pièce et sa superficie, sous la forme Pièce n : nom (superficie). Par exemple, pour la première itération : Pièce 1 : cuisine (18.0 m**2).

Hide code cell source
for i, L in enumerate(maison):
    print("Pièce " + str(i + 1) + " : " + L[0] + " (" + str(L[1]) + " m**2)")
Pièce 1 : cuisine (18.0 m**2)
Pièce 2 : salon (20.0 m**2)
Pièce 3 : chambre (10.75 m**2)
Pièce 4 : salle de bains (9.5 m**2)

Itérer sur un dictionnaire#

Il est très simple d’itérer sur un dictionnaire avec la méthode .items() :

# Création d'un dictionnaire
dic_taille_plantes = {"gentiane"  : 7.5, 
                      "campanule" : 5.8,
                      "pensée"    : 11.4}

# Itérer sur le dictionnaire
for key, values in dic_taille_plantes.items():
    print(key + " -- " + str(values) + " cm")
gentiane -- 7.5 cm
campanule -- 5.8 cm
pensée -- 11.4 cm

Itérer sur un tableau Numpy#

Pour itérer sur un tableau 1D c’est aussi simple que :

# Importation du module numpy
import numpy as np

# Création du tableau Numpy
A = np.array([4, 6, 1])

# Itérer sur le tableau Numpy
for i in A:
    print(i)
4
6
1

Si on veut itérer sur tous les éléments d’un tableau 2D, on peut utiliser la fonction Numpy nditer() :

# Création du tableau Numpy à 2 dimensions
B = np.array([[1, 7],
              [8, 0]])

# Itérer sur tous les éléments du tableau 2D
for x in np.nditer(B):
    print(x)
1
7
8
0

Itérer sur un DataFrame#

Il est possible d’itérer sur les différentes lignes d’un DataFrame en utilisant la méthode .iterrows().

Par exemple, créons un DataFrame à partir d’un dictionnaire donnant les tailles de 3 de nos plantes pendant 4 jours, avec une observation par jour :

# Importation du module Pandas
import pandas as pd

# Création d'un dictionnaire
dic_taille_plantes = {"gentiane"  : [7.5, 7.8, 8.3, 8.4], 
                      "campanule" : [5.8, 6.6, 7.4, 8.3],
                      "pensée"    : [11.4, 11.6, 11.7, 11.7]}

# Création du DataFrame
df_taille_plantes = pd.DataFrame(data = dic_taille_plantes, index = range(1, 5))

Voici notre DataFrame :

df_taille_plantes
gentiane campanule pensée
1 7.5 5.8 11.4
2 7.8 6.6 11.6
3 8.3 7.4 11.7
4 8.4 8.3 11.7

sur lequel nous itérons chaque observation (une observation par jour, en commençant par le jour 1) :

for label, row in df_taille_plantes.iterrows():
    print("jour", label)
    print(row)
    print()
jour 1
gentiane      7.5
campanule     5.8
pensée       11.4
Name: 1, dtype: float64

jour 2
gentiane      7.8
campanule     6.6
pensée       11.6
Name: 2, dtype: float64

jour 3
gentiane      8.3
campanule     7.4
pensée       11.7
Name: 3, dtype: float64

jour 4
gentiane      8.4
campanule     8.3
pensée       11.7
Name: 4, dtype: float64

Dans la boucle, la variable row extrait avec la méthode .iterrows() est un objet de type Series. Cet objet est construit avec comme Index le nom des colonnes, et comme nom l’Index de la ligne correspondante du DataFrame. Le tableau est en quelque sorte renversé pour produire une série d’observations pour chaque jour.

Il est alors facile d’extraire les observations correspondant seulement à une plante donnée :

for label, row in df_taille_plantes.iterrows():
    print("jour " + str(label) + " : " + str(row["gentiane"]))
jour 1 : 7.5
jour 2 : 7.8
jour 3 : 8.3
jour 4 : 8.4

Il est aussi possible d’itérer sur les colonnes de l’objet DataFrame avec la méthode .iteritems() :

for label, col in df_taille_plantes.iteritems():
    print("Plante : " + label)
    print(col)
    print()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_2188/138948646.py in ?()
----> 1 for label, col in df_taille_plantes.iteritems():
      2     print("Plante : " + label)
      3     print(col)
      4     print()

/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/pandas/core/generic.py in ?(self, name)
   5985             and name not in self._accessors
   5986             and self._info_axis._can_hold_identifiers_and_holds_name(name)
   5987         ):
   5988             return self[name]
-> 5989         return object.__getattribute__(self, name)

AttributeError: 'DataFrame' object has no attribute 'iteritems'

On voit que la variable col est un objet Series contenant toutes les observations correspondant à une colonne donnée, c’est-à-dire à une plante donnée.

Exercice#

Importons les données sauvées dans le fichier pickle contenant l’objet DataFrame sur les pays de l’Union Européenne :

df_europe = pd.read_pickle('./europe.pkl')
  1. Créer une copie de cet objet appelée df_europe_cp avec la méthode .copy()

  2. À l’aide d’une boucle for, écrire chaque pays et capitale sous la forme Pays : Capitale (avec une majuscule pour la première lettre, on peut utliser la méthode .capitalize()). Par exemple pour la première itération : Allemagne : Berlin.

Hide code cell source
# 1. Copie du DataFrame
df_europe_cp = df_europe.copy(deep = True) # deep = True est optionnel mais c'est toujours mieux de faire une copie profonde plutôt qu'une copie superficielle

# 2. Liste des pays et de leur capitale
for label, row in df_europe_cp.iterrows():
    print(row["pays"].capitalize() + " : " + row["capitale"].capitalize())