Itération

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

Mise à jour d’une variable

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

[1]:
# creation 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:

[2]:
# 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’instruction (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’instruction 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’instruction n’est pas exécuté et on passe à la première instruction après le while qui n’est pas indentée.

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’instruction (indenté) suivant l’instruction while, et poursuivre l’exécution à l’instruction suivante ;
  3. Si la condition est vraie, exécutez le bloc d’instruction, puis retournez à l’étape 1.

Ce type de flux est une boucle car l’étape 3 reboucle à l’étape 1. Le bloc d’instruction 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’instruction 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. A la sortie de la boucle, afficher à l’écran la valeur de x.

[3]:
# 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’instruction, 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:

[4]:
# 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.

[5]:
# initialisation
x = 41

# boucle while
while x > 1:
    if x % 2 != 0:
        print("x doit être pair")
        break
    x = x / 4.0
x doit être pair

L’instruction for

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

[6]:
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 [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():

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

Exercice

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

[8]:
for i in range(1,5):
    print(4*i)
4
8
12
16
[9]:
# ou bien
for i in range(1,20):
    if i % 4 == 0:
        print(i)
4
8
12
16

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:

[10]:
# creation d'une liste
L = ['b', 2, True, 5.897]

# iteration sur les elements 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():

[11]:
# iteration sur les indices et les elements 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 itérer sur une liste de liste:

[12]:
# creation 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 liste donnant les superficie en m**2 des pièces d’une maison:

[13]:
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).

[14]:
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():

[15]:
# creation d'un dictionnaire
dic_taille_plantes = {"gentiane"  : 7.5,
                      "campanule" : 5.8,
                      "pensée"    : 11.4}

# iterer 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:

[16]:
# importation du module numpy
import numpy as np

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

# iterer 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():

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

# iterer sur tous les elements 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 observations 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:

[18]:
# importation du module Pandas
import pandas as pd

# creation 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:

[19]:
df_taille_plantes
[19]:
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):

[20]:
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:

[21]:
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():

[22]:
for label, col in df_taille_plantes.iteritems():
    print("Plante: " + label)
    print(col)
    print()
Plante: gentiane
1    7.5
2    7.8
3    8.3
4    8.4
Name: gentiane, dtype: float64

Plante: campanule
1    5.8
2    6.6
3    7.4
4    8.3
Name: campanule, dtype: float64

Plante: pensée
1    11.4
2    11.6
3    11.7
4    11.7
Name: pensée, dtype: float64

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:

[23]:
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. A 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.
[24]:
# 1. copie du DataFrame
df_europe_cp = df_europe.copy()

# 2. Liste des pays et de leur capitale
for lab, row in df_europe_cp.iterrows():
    print(row["pays"].capitalize() + ": " + row["capitale"].capitalize())
Allemagne: Berlin
Autriche: Vienne
Belgique: Bruxelles
Bulgarie: Sofia
Chypre: Nicosie
Croatie: Zagreb
Danemark: Copenhague
Espagne: Madrid
Estonie: Tallinn
Finlande: Helsinki
France: Paris
Grèce: Athènes
Hongrie: Budapest
Irlande: Dublin
Italie: Rome
Lettonie: Riga
Lituanie: Vilnius
Luxembourg: Luxembourg
Malte: La valette
Pays-bas: Amsterdam
Pologne: Varsovie
Portugal: Lisbonne
République tchèque: Prague
Roumanie: Bucarest
Slovaquie: Bratislava
Slovénie: Ljubljana
Suède: Stockholm