Informatique et Calcul Scientifique

Cours 3

Author

Leonard Hardiman et Ghid Maatouk

Boucles et itérations

Outre les conditions if/else/elif, l’autre moyen important d’influencer le flux de contrôle est avec les boucles et itérations.

  • Ces structures permettent de répéter une portion de code un certain nombre de fois.

  • Commençons par la boucle while, qui permet de répéter une portion de code tant qu’une certaine condition est True.

L’instruction while

L’instruction while permet de répéter un bloc d’instructions tant qu’une condition est évaluée à True. C’est ce qu’on appelle une boucle.

def compte_a_rebours(n):
    print('Début du compte à rebours depuis', n)
    
    while n > 0:
        print(n)
        n = n - 1  # Décrémentation importante !
    
    print('Décollage !')

compte_a_rebours(5)
Début du compte à rebours depuis 5
5
4
3
2
1
Décollage !

Remarque. N’oubliez pas les deux-points après la condition et l’indentation du bloc de code.

Attention aux boucles infinies !

Une boucle infinie se produit quand la condition d’un while reste toujours True. La boucle va itérer à l’infini et le programme ne s’arrêtera jamais !

def compte_a_rebours(n):
    print('Début du compte à rebours depuis', n)
    
    while n > 0:
        print(n)
        # On oublie le décrémentation !
    
    print('Décollage !')

compte_a_rebours(5)

Remarque. Vérifiez toujours que votre variable de contrôle est modifiée dans la boucle, sinon la condition ne changera jamais. Il faut généralement éviter les boucles de la forme while True:...

Example d’un calcul avec while

Les boucles while sont utiles pour effectuer des calculs répétitifs. Voici un exemple qui calcule la somme des n premiers nombres entiers.

def somme_premiers_nombres(n):
    somme = 0
    compteur = 1
    
    while compteur <= n:
        somme = somme + compteur
        compteur += 1
    
    return somme

somme_premiers_nombres(10)
55

Explication. Cette fonction calcule 1 + 2 + 3 + ... + n. À chaque itération de la boucle, on ajoute la valeur de compteur à somme, puis on incrémente compteur. La boucle s’arrête quand compteur dépasse n.

L’instruction break

L’instruction break permet de sortir immédiatement d’une boucle while, même si la condition est encore True. C’est utile pour arrêter une boucle selon une condition particulière.

def ppmc(a, b):
    x = 1
    
    while True:
        if x % a == 0 and x % b == 0: break
        x = x + 1
    
    return x

ppmc(4, 6)
12

Remarque. L’instruction break peut être utile, mais en général il vaut mieux l’éviter. Il vaut mieux être plus précis lors du choix de notre condition while.

Introduction aux boucles for

La boucle for s’utilise quand on veut exécuter une portion de code un nombre connu de fois. Elle est idéale pour itérer sur des séquences de valeurs prédéfinies.

for i in range(5):
    print('Bonjour!')
Bonjour!
Bonjour!
Bonjour!
Bonjour!
Bonjour!
for i in range(5):
    if not i % 2 :
        print('Bonjour')
    else:
        print('Bonne nuit!!')
Bonjour
Bonne nuit!!
Bonjour
Bonne nuit!!
Bonjour
  • i est la variable d’itération (peut avoir n’importe quel nom).
  • range(5) est une structure itérable contenant les valeurs 0, 1, 2, 3, 4.
  • À chaque itération, i prend la valeur suivante de la séquence.

La fonction range

Pour n un entier arbitraire, range(n) contient les valeurs 0, 1, . . . , n-1.

  • range(5) contient : 0, 1, 2, 3, 4.
  • range(1) contient : 0 seulement.
  • range(0), range(-1) et range(-2) sont vides.

Pour i et j deux entiers, range(i,j) contient les valeurs i, i+1, . . . , j-1.

  • range(2,6) contient : 2, 3, 4, 5.
  • range(3,4) contient : 3 seulement.
  • range(5,5) et range(6,2) sont vides.

La fonction range Pt. 2

range(i, j, k) crée une séquence allant de i à j avec un pas de k.

for i in range(-2, 11, 3):
    print(i, end=' ')
-2 1 4 7 10 
  • i, j et k doivent tous être des nombres entiers.
  • Le pas k peut être négatif, mais pas 0.
def compte_a_rebours(n):
    print('Début du compte à', n)
    for i in range(n, 0, -1):
        print(i)
    print('Décollage !')

compte_a_rebours(3)
Début du compte à 3
3
2
1
Décollage !

Remarque. range(0, n, 1), range(0, n) et range(n) sont identiques.

Boucle while vs boucle for

On peut toujours simuler une boucle for avec une boucle while :

for i in range(3, 12, 2):
    print(i, end=' ')

print('\n----------')

k = 3
while k < 12:
    print(k, end=' ')
    k += 2
3 5 7 9 11 
----------
3 5 7 9 11 

Quand utiliser chaque type ?

  • Boucle for : quand on connaît le nombre d’itérations à l’avance,
  • Boucle while : sinon.

Exemple : multiples de 19

Afficher tous les multiples de 19 entre 0 et 1000 :

  • avec une boucle for,

    {python} for i in range(1001): if i % 19 == 0: print(i, end=' ')

  • avec une boucle while,
i = 0
while i <= 1000:
    if i % 19 == 0:
        print(i, end=' ')
    i += 1
0 19 38 57 76 95 114 133 152 171 190 209 228 247 266 285 304 323 342 361 380 399 418 437 456 475 494 513 532 551 570 589 608 627 646 665 684 703 722 741 760 779 798 817 836 855 874 893 912 931 950 969 988 

Remarque. La boucle for avec range() offre une syntaxe plus concise et claire pour de nombreux cas d’usage courants.

Autres structures itérables

  • Nous avons vu que range(n) est une structure itérable, donc nous pouvons la parcourir avec une boucle for.

  • Mais ce n’est pas la seule structure itérable ! En fait, nous en avons déjà vu une : str.

for c in 'pizza':
    print(c, end=' ')
p i z z a 
for c in 'pizza':
    print(c * 3, end=' ')
ppp iii zzz zzz aaa 

str : indexage

Les str sont des objets indexables. En particulier, nous pouvons les indexer par i pour obtenir le ième caractère.

s = "J'ai l'impression que nous ne sommes plus au Kansas"
print(s[0])
print(s[6])
J
'

Nous pouvons donc indexer une str par n’importe quel entier de 0 à n-1, où n est la longueur de la str.

s = "J'ai l'impression que nous ne sommes plus au Kansas"
for i in range(len(s)):
    print(s[i], end='')
J'ai l'impression que nous ne sommes plus au Kansas

Cela donne une autre façon de parcourir les caractères d’une str, qui nous permet aussi de parcourir à l’envers.

s = "J'ai l'impression que nous ne sommes plus au Kansas"
n = len(s)
for i in range(n):
    print(s[n-1-i], end='')
sasnaK ua sulp semmos en suon euq noisserpmi'l ia'J

Ou, de manière équivalente,

s = "J'ai l'impression que nous ne sommes plus au Kansas"
for i in range(len(s)-1, -1, -1):
    print(s[i], end='')
sasnaK ua sulp semmos en suon euq noisserpmi'l ia'J

Remarque. len est une fonction built-in de Python qui retourne la longueur de plusieurs structures différentes.

Les tuples : introduction

  • Un tuple est une structure qui permet de regrouper plusieurs objets dans un seul objet.
  • Les tuples se créent avec des parenthèses () et les éléments sont séparés par des virgules.
coordonnées = (3, 7)
print(coordonnées)

personne = ('Alice', 25, 'Ingénieure')
print(personne)
(3, 7)
('Alice', 25, 'Ingénieure')

Remarque. Un tuple peut contenir des éléments de types différents : int, float, str

Indexage des tuples

  • Comme les str, les tuples sont indexables. On peut accéder à chaque élément par sa position.
  • Comme d’habitude, l’indexation commence à 0 pour le premier élément.
point = (10, 20, 30)
print('x =', point[0])
print('y =', point[1]) 
print('z =', point[2])

print('Longueur du tuple:', len(point))
x = 10
y = 20
z = 30
Longueur du tuple: 3

Remarque. Comme pour les str, essayer d’accéder à un index qui n’existe pas provoque une erreur. De même, on peut faire des calculs sur un tuple: len, max, min, sum

Unpacking de tuples

Python permet de unpack (déballer) un tuple en assignant ses éléments à plusieurs variables en une seule fois. Par exemple,

coordonnées = (5, 10)
x, y = coordonnées  # Unpacking du tuple
print('x =', x, ';', 'y =', y)
x = 5 ; y = 10

est équivalent à

coordonnées = (5, 10)
x = coordonnées[0]
y = coordonnées[1]
print('x =', x, ';', 'y =', y)
x = 5 ; y = 10

Important. Le nombre de variables à gauche doit correspondre exactement au nombre d’éléments dans le tuple.

Unpacking : ce que vous connaissez déjà

En fait, vous avez déjà utilisé le unpacking de tuples sans le savoir !

  • dans les affectations multiples
  • dans les fonctions qui retournent plus d’un objet
# Affectation multiple
a, b, c = 1, 2, 3  # Crée un tuple (1, 2, 3) puis le unpack
print('a =', a)
print('b =', b) 
print('c =', c)
a = 1
b = 2
c = 3
# Fonction qui retourne plusieurs valeurs
def calculer_cercle(rayon):
    aire = 3.14 * rayon * rayon
    périmètre = 2 * 3.14 * rayon
    return aire, périmètre  # Retourne un tuple !

# Unpacking du résultat de la fonction
aire_cercle, périmètre_cercle = calculer_cercle(4)
print('Aire:', aire_cercle)
print('Périmètre:', périmètre_cercle)
Aire: 50.24
Périmètre: 25.12

Remarque. Quand une fonction retourne plusieurs objets séparées par des virgules, elle retourne en réalité un tuple.

Remarque. En réfléchissant aux tuples, on voit que l’affectation multiple permet d’échanger les valeurs de deux variables, sans avoir besoin d’une variable temporaire.

x = 10
y = 20
print('Avant échange:', 'x =', x, 'y =', y)

x, y = y, x  # Équivaut à : x, y = (y, x)

print('Après échange:', 'x =', x, 'y =', y)
Avant échange: x = 10 y = 20
Après échange: x = 20 y = 10

Fonctions avec un nombre variable de paramètres

  • Les tuples permettent aux fonctions d’accepter un nombre arbitraire d’arguments en utilisant l’opérateur * (appelé “étoile”).
def saluer(*personnes):
    if len(personnes) == 0:
        print("Personne à saluer !")
    elif len(personnes) == 1:
        print("Bonjour", personnes[0], "!")
    else:
        print("Bonjour à tous les", len(personnes), "amis!")

saluer()
saluer("Leonard")
saluer("Leonard", "Ghid", "Sam")
Personne à saluer !
Bonjour Leonard !
Bonjour à tous les 3 amis!
  • Quand une fonction utilise *args, tous les arguments suivants doivent être appelés par nom.
def moyenne(*nombres, afficher=False):
    if not nombres:
        return None
    moyenne = sum(nombres) / len(nombres)
    if afficher:
        print('Moyenne de', nombres, '=', moyenne)
    return moyenne

x = moyenne(10, 20, 30)
y = moyenne(5, 15, 25, afficher=True)
z = moyenne(5, 15, 25, True)        # Erreur silencieuse !
print('x =', x,'y =', y,'z =', z)
Moyenne de (5, 15, 25) = 15.0
x = 20.0 y = 15.0 z = 11.5

Remarque. Cette règle évite l’ambiguïté : sinon Python ne peut pas savoir si un argument fait partie du tuple *args ou s’il correspond à un paramètre suivant.

Itération sur les tuples

  • Les tuples sont aussi des structures itérables, donc on peut les parcourir avec une boucle for.
from fonctions_ics import fonctionDeSam
choses = ('La fondue', 'La raclette', 3.14)
for chose in choses:
    fonctionDeSam(chose)

La fondue est mieux au Valais!
La raclette est mieux au Valais!
3.14 est mieux au Valais!

  • On peut aussi parcourir un tuple en utilisant les indices :
températures = (18, 22, 25, 19)

for i in range(len(températures)):
    print('Jour', i+1, ':', températures[i], '°C')
Jour 1 : 18 °C
Jour 2 : 22 °C
Jour 3 : 25 °C
Jour 4 : 19 °C

Boucles imbriquées

  • Il est possible d’imbriquer des boucles for.
  • La boucle interne s’exécute complètement pour chaque itération de la boucle externe.
for i in range(1, 4):
    for j in range(1, 5):
        result = i + j
        print(i, '+', j, '=', i+j, end='; ')
    print()  # nouvelle ligne
1 + 1 = 2; 1 + 2 = 3; 1 + 3 = 4; 1 + 4 = 5; 
2 + 1 = 3; 2 + 2 = 4; 2 + 3 = 5; 2 + 4 = 6; 
3 + 1 = 4; 3 + 2 = 5; 3 + 3 = 6; 3 + 4 = 7; 

Remarque. Le range de la boucle intérieure peut dépendre de la variable d’itération de la boucle extérieure.

for i in range(1, 4):
    for j in range(i+1, 7):
        print((i,j), end=' | ')
    print()  # nouvelle ligne
(1, 2) | (1, 3) | (1, 4) | (1, 5) | (1, 6) | 
(2, 3) | (2, 4) | (2, 5) | (2, 6) | 
(3, 4) | (3, 5) | (3, 6) | 

Exemple final

Écrivons une fonction qui…

  • accepte un entier de 1 à 9,
  • compte jusqu’à ce entier en utilisant les adjectifs numéraux épelés sans voyelles.
from fonctions_ics import adjectif_numéral

def afficher_numéraux_sans_voyelles(n):
    if not (type(n)==int and 0 < n < 10):
        print('Erreur: n doit être un entier entre 1 et 9 inclus')
        return False
    for i in range(1,n+1):
        s = adjectif_numéral(i)
        for c in s:
            if c not in 'aeiou':
                print(c, end='')
        print()

afficher_numéraux_sans_voyelles(7)

n
dx
trs
qtr
cnq
sx
spt

Remarque. Le keyword in peut également être utilisé pour créer des conditions booléennes.