La loop for en Python sert à exécuter un bloc de code de manière répétée. Les boucles for sont un élément fon­da­men­tal de la plupart des langages de pro­gram­ma­tion. Nous montrons comment fonc­tionne la boucle for en Python et comment l’utiliser.

Nom de domaine
Votre domaine en un clic
  • 1 cer­ti­fi­cat SSL Wildcard par contrat
  • Fonction incluse Domain Connect pour une con­fi­gu­ra­tion DNS sim­pli­fiée

Qu’est-ce que la loop for en Python ?

La boucle for est, avec l’em­bran­che­ment if-else, la technique de pro­gram­ma­tion la plus connue. Des gé­né­ra­tions de pro­gram­meurs se sont démenés pour dé­ve­lop­per le concept in­for­ma­tique de la boucle. En effet, les boucles sont au départ peu in­tui­tives. Pourtant, les problèmes de com­pré­hen­sion pro­vien­nent peut-être davantage de la manière avec laquelle le concept est présenté. Car en soi, les boucles n’ont rien de très par­ti­cu­lier.

Illustrer le concept de la boucle par un exemple concret sert cependant à la com­pré­hen­sion. Imaginons une classe d’école : l’en­seig­nant souhaite dé­ter­mi­ner la taille moyenne des enfants dans le cadre d’une ex­pé­rience. Pour ce faire, il demande à chaque enfant sa taille au fur et à mesure et ad­di­tionne les dif­fé­rentes tailles pour obtenir une somme. Ensuite, il divise la somme par le nombre d’enfants pour obtenir la taille moyenne. Nous faisons un al­go­rithme simple à partir de la procédure de l’en­seig­nant :

  1. Demander la taille de chaque enfant et l’ajouter à la somme
  2. Diviser la somme par le nombre d’enfants

La première étape est effectuée une fois pour chaque enfant et dépend donc du nombre d’enfants dans la classe. La deuxième étape n’est exécutée qu’une seule fois, in­dé­pen­dam­ment du nombre d’enfants dans la classe. Nous avons besoin d’une boucle pour la première étape. Voici un exemple de code qui calcule la taille moyenne d’un écolier avec un loop for en Python :

children_heights = [155, 171, 148, 161, 158, 153, 162]
height_sum = 0
for height in children_heights:
    height_sum = height_sum + height
average_height = height_sum // len(children_heights)
print(average_height)

La loop for en Python exécute un bloc de code de manière répétée. On parle également d’« itération ». Les boucles per­met­tent notamment de traiter in­di­vi­duel­le­ment, selon le même schéma, plusieurs éléments regroupés dans une même « col­lec­tion ». Une boucle for est donc utilisée lorsque tous les éléments de la col­lec­tion peuvent être dé­ter­mi­nés pendant l’exécution du programme. Si ce n’est pas le cas, alors une boucle while est re­com­man­dée.

Conseil

Apprenez à utiliser le langage de pro­gram­ma­tion Python avec notre tutoriel Python!

Qu’est-ce qui dif­fé­ren­cie la loop for de Python des autres langages ?

De nombreux langages de pro­gram­ma­tion con­nais­sent le concept de la boucle for. Il s’agit d’une cons­truc­tion fon­da­men­tale dans d’autres langages comme C, Java, Ja­vaS­cript et PHP. Les langages purement fonc­tion­nels comme Haskell ou Lisp n’ont gé­né­ra­le­ment pas de boucle for. Au lieu de l’itération, ces langages utilisent des fonctions ré­cur­sives.

Toutes les boucles ont en commun une chose : un bloc de code est exécuté de manière répétée. Cependant, le fonc­tion­ne­ment de la loop for en Python se distingue nettement des autres. La plupart des langages de pro­gram­ma­tion utilisent une variable de boucle qui est in­cré­men­tée ou dé­cré­men­tée lorsque la boucle est exécutée.

Action Sig­ni­fi­ca­tion Re­pré­sen­ta­tion ordinaire Re­pré­sen­ta­tion en Python
In­cré­men­ta­tion Augmenter la valeur d’une variable entière d’un montant fixe déterminé i++ index += 1
Dé­cré­men­ta­tion Diminuer la valeur d’une variable entière d’un montant fixe déterminé i-- index -= 1

Prenons un exemple pour voir comment fonc­tionne une boucle for dans d’autres langages. Nous prenons tout d’abord les nombres de 0 à 9 en Ja­vaS­cript avec une boucle for. Une variable entière 'number' est ensuite définie et on l’in­cré­mente tant que le nombre qu’elle contient est inférieur à 10. Le code utilisé pour cette opération semble plutôt complexe pour les débutants :

for ( let number = 0; number < 10; number++ ) {
    console.log(number);
}

Alors que le code d’une boucle for cor­res­pon­dante en Python semble nettement plus clair :

for number in range(10):
    print(number)

Au lieu d’afficher di­rec­te­ment la valeur de la variable de boucle, celle-ci est gé­né­ra­le­ment utilisée pour indexer un élément au sein d’une col­lec­tion. Prenons à nouveau un exemple en Ja­vaS­cript : nous affichons les noms contenus dans la liste 'people' les uns après les autres. Pour cela, nous utilisons la variable de boucle 'i' comme index continu des dif­fé­rents éléments :

people = ['Jack', 'Jim', 'John']
for (let i = 0; i < people.length; i++) {
    console.log("Here comes " + people[i]);
}

Indexer di­rec­te­ment des éléments de liste sé­quen­tiels doit être fait avec prudence. En effet, une tentative d’accès en dehors des limites au­to­ri­sées entraîne une erreur d’exécution. En règle générale, il s’agit de la fameuse « Off-by-one Error ». Python montre qu’il est possible de faire autrement. Voici le même exemple avec une boucle for en Python : nous itérons di­rec­te­ment sur les éléments de la liste, sans les indexer avec une variable de la boucle :

people = ['Jack', 'Jim', 'John']
for person in people:
    print(f"Here comes {person}")

La valeur indirecte de la variable de boucle contribue largement à la com­plexité de l’ap­pren­tis­sage des boucles for dans d’autres langages. En effet, la variable de boucle centrale ne nous intéresse gé­né­ra­le­ment pas. Elle ne sert qu’à indexer les dif­fé­rents éléments. L’uti­li­sa­tion des boucles for tra­di­tion­nelles nécessite la com­pré­hen­sion de plusieurs sujets complexes. Prenons l’exemple de Ja­vaS­cript :

Thème Re­pré­sen­ta­tion dans la boucle for Ja­vaS­cript
Déclarer une variable let i = 0
Ex­pres­sions boo­léennes i < limit
Outil d’in­cré­men­ta­tion et de dé­cré­men­ta­tion i++ / i--
Dé­ter­mi­ner la taille d’une col­lec­tion i < list.length
In­dexa­tion d’éléments à partir de zéro i < list.length est OK; i <= list.length mène à Off-by-one Error

La boucle for en Python est nettement plus simple d’uti­li­sa­tion. Même si le mot-clé 'for' est utilisé, il s’agit d’une approche fon­da­men­ta­le­ment dif­fé­rente. Au lieu d’in­cré­men­ter une variable de la boucle et d’indexer ainsi suc­ces­si­ve­ment des éléments, nous itérons di­rec­te­ment sur les éléments d’une col­lec­tion. La loop for en Python est ainsi com­pa­rable à la cons­truc­tion forEach de certains langages comme Ruby et Ja­vaS­cript.

Pour illustrer notre propos, donnons les dif­fé­rentes lettres d’un mot. Dans la boucle for, une lettre du mot est placée dans la variable 'letter' à chaque passage de la boucle. Cela fonc­tionne sans variable de boucle et donc sans risque de produire une erreur off-by-one. Le code est précis et facile à lire :

word = "Python"
for letter in word:
    print(letter)

Comment fonc­tionne une loop for en Python ?

Comme nous l’avons vu, la loop for en Python résout ef­fi­ca­ce­ment le problème de l’itération sur les éléments d’une col­lec­tion. Pour ce faire, nous n’avons donc pas besoin de passer par une variable de boucle numérique. C’est certes un très bon point, mais comment cela fonc­tionne-t-il exac­te­ment ? Pour com­prendre le principe de fonc­tion­ne­ment de la loop for en Python, il faut connaître les concepts d’itérable et d’itérateur.

Qu’est-ce que l’itérable, l’itérateur et le gé­né­ra­teur ?

La loop for de Python opère sur des objets connus sous le nom d’« itérables ». Il s’agit de chaînes de ca­rac­tères, de listes, de tuples et d’autres types de données com­po­sites. Selon les termes de la do­cu­men­ta­tion of­fi­cielle de Python :

Citation

"[An iterable is] an object capable of returning its members one at a time"/ Source : https://docs.python.org/3/glossary.html#term-iterable

Tra­duc­tion : « [Un itérable est] un objet dont on peut parcourir les valeurs une à une » (traduit par IONOS)

Un objet itérable a deux pro­prié­tés :

  1. Il regroupe plusieurs éléments pour former une col­lec­tion
  2. Il donne un accès à ses éléments via une interface appelée « itérateur »

Ensemble, cela signifie que les itérables sont des col­lec­tions dont le contenu peut être itéré. Une itérable possède spé­ci­fi­que­ment une méthode '__iter__()' qui renvoie un itérateur. L’itérateur est un objet qui fournit sur commande l’élément suivant de l’itérable. De plus, un itérateur rappelle la position du dernier élément renvoyé dans la col­lec­tion.

Fonction Ex­pli­ca­tion Exemple
iter(col­lec­tion) Appelle la méthode __iter__() de la col­lec­tion it = iter("Python")
next(iter) Appelle la méthode __next__() de l'ité­ra­teur next(it)
col­lec­tion[index] Appelle la méthode __getitem__(index) de la col­lec­tion 'Python'[1]

Un itérateur renvoie à l’élément suivant lors de l’appel de la méthode __next__(). Si tous les éléments de la col­lec­tion ont été livrés, l’itérateur est épuisé. Un autre appel à __next__() déclenche une exception 'S­to­pI­te­ra­tion'.

Con­si­dé­rons le fonc­tion­ne­ment d’un itérateur à l’aide d’un exemple. Nous créons un objet range() qui re­pré­sente les nombres con­sé­cu­tifs 21 à 23. Ensuite, nous créons un itérateur à l’aide de la fonction iter() et nous sortons des éléments suc­ces­sifs à l’aide de la fonction next(). Lors du dernier appel, l’exception est levée car l’itérateur est épuisé :

numbers = range(21, 24)
number = iter(numbers)
next(number)
# returns '21'
next(number)
# returns '22'
next(number)
# returns '23'
next(number)
# raises 'StopIteration' exception

Un itérateur donne accès à des éléments in­di­vi­duels d’une col­lec­tion. Python connaît également le concept similaire de « gé­né­ra­teur ». La dif­fé­rence réside dans le fait qu’un gé­né­ra­teur ne crée des éléments in­di­vi­duels qu’au moment de l’accès. Cela permet surtout d’éco­no­mi­ser de la mémoire lors de l’exécution du programme, c’est pourquoi on parle aussi de « lazy ge­ne­ra­tion ».

Un gé­né­ra­teur en Python est basé sur une fonction qui utilise l’ins­truc­tion Yield. Celle-ci renvoie un objet de la même manière que l’ins­truc­tion return et met fin à l’appel de la fonction. Lors d’un nouvel appel, la fonction de gé­né­ra­teur ne re­com­mence cependant pas depuis le début, mais continue après la dernière ins­truc­tion yield.

L’exemple suivant illustre ces propos. Nous écrivons notre propre version de la fonction range(). Nous utilisons l’ins­truc­tion yield dans une boucle while pour générer des nombres continus :

def my_range(start, stop):
    if stop < start:
        return None
    current = start
    while current < stop:
        yield current
        current += 1
# test
assert list(my_range(7, 9)) == list(range(7, 9))

Sauter et annuler un passage de la loop for en Python

Dans la pratique, il est parfois né­ces­saire d’ignorer un seul passage de la boucle. Comme beaucoup d’autres langages, Python contient l’ins­truc­tion « continue ». Lors de l’appel de continue dans le corps de la boucle, l’itération en cours est in­ter­rom­pue. La boucle commence alors im­mé­dia­te­ment l’itération suivante.

Une ins­truc­tion continue peut être utilisée de manière similaire au early-return lors de l’appel d’une fonction. Par exemple, nous sautons une itération dès que nous cons­ta­tons qu'un ensemble de données n'a pas la qualité requise :

def process_data(data):
    for data_set in data:
        data_set.validate()
        # early continue after cheap check fails
        if not data_set.quality_ok():
            continue
        # expensive operation guarded by early continue
        data_set.process()

Un autre exemple : nous prenons un texte et sautons une lettre sur deux :

text = 'Skipping every second letter'
for index, letter in enumerate(text):
    if index % 2 != 0 and letter != ' ':
        continue
    print(letter)

En plus de l’ins­truc­tion continue pour sauter un passage de la boucle, il existe l’ins­truc­tion break. Un appel à break à l’intérieur du corps de la boucle in­ter­rompt im­mé­dia­te­ment la suite de l’exécution de la boucle. Ainsi, break a une fonction similaire pour les boucles que l’ins­truc­tion return pour les fonctions.

L’ins­truc­tion break est souvent utilisée pour mettre en œuvre des al­go­rithmes de recherche. Si un élément recherché est trouvé dans une boucle, il est inutile de continuer à itérer. De la même manière que pour la fonction any(), nous vérifions la présence d’une seule valeur True dans une liste. Avec break, on s’arrête dès que nous avons trouvé quelque chose :

bool_list = [False, False, True, False]
for index, boolean in enumerate(bool_list):
    if boolean:
        print(f"Value at position {index + 1} is True")
        print(f"Aborting inspection of remaining {len(bool_list) - index - 1} item(s)")
        break

En relation avec l’ins­truc­tion break, une loop for en Python peut être dotée d’un corps else optionnel. Le code qu’il contient est exécuté lorsque la boucle se termine sans qu’une ins­truc­tion break ait été exécutée :

def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you’re looking for")
            break
    else:
        print("Didn’t find what you were looking for")
# test
find_element('a', 'Python')
find_element('o', 'Python')

Les boucles for sont souvent utilisées en Python à l’intérieur de corps de fonctions. Dans ce cas, il est courant d’utiliser une ins­truc­tion return au lieu d’une ins­truc­tion break. Notre al­go­rithme de recherche reformule sans utiliser break et else :

def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you’re looking for")
            # returning breaks us out of the loop
            return element
    # we made it here without returning
    print("Didn’t find what you were looking for")
    return None
# test
print(find_element('a', 'Python'))
print(find_element('o', 'Python'))

Quelles sont les meil­leures façons d’utiliser les loops for en Python ?

Les loops for en Python servent en premier lieu à itérer sur les éléments d’une séquence ou d’une col­lec­tion. Il existe des méthodes plus directes pour de nombreux cas d’ap­pli­ca­tion courants. Nous pré­sen­tons les meil­leures pratiques et les an­ti­pat­terns im­por­tants. Tout d’abord, un aperçu des termes clés :

Terme Ex­pli­ca­tion Exemple
Col­lec­tion Re­grou­pe­ment de plusieurs éléments ; une col­lec­tion est une itérable ('Walter', 'White'), [4, 2, 6, 9], 'Python'
Itérateur Interface pour itérer sur les col­lec­tions it = iter('Python')
Gé­ne­ra­teur Une fonction qui utilise yield au lieu de l’ins­truc­tion return ; un gé­né­ra­teur est itérable range(10)
Com­pré­hen­sion Ex­pres­sion itérative ; crée une nouvelle col­lec­tion basée sur une itérable [num ** 2 for num in range(10)]

Itérer di­rec­te­ment sur les éléments d’une col­lec­tion

Une erreur fréquente des pro­gram­meurs inex­pé­ri­men­tés est d’abuser de la loop for en Python. Comme c’est souvent le cas dans d’autres langages, ils utilisent la fonction len() comme limite de la fonction range() pour créer une variable numérique en boucle. Ils s’en servent pour indexer les dif­fé­rents éléments de la col­lec­tion :

word = 'Python'
for i in range(len(word)):
    print(word[i])

Cet an­ti­pat­tern est réprouvé pour une bonne raison : il n’est pas pythonien. En effet, il est pré­fé­rable d’itérer di­rec­te­ment sur les éléments de la col­lec­tion avec la loop for de Python :

word = 'Python'
for letter in word:
    print(letter)

Énumérer les éléments d’une col­lec­tion avec enumerate() et leur index

On a parfois besoin de l’index d’un élément dans une col­lec­tion. Au lieu de créer l’index comme variable de boucle, nous utilisons la fonction enumerate(). Celle-ci renvoie le tuple (index, élément). Il faut noter que l’index commence à compter à partir de zéro :

names = ["Jim", "Jack", "John"]
for index, name in enumerate(names):
    print(f"{index + 1}. {name}")

Utiliser la fonction zip() pour itérer sur des tuples d’éléments.

Un autre scénario fré­quem­ment rencontré est l’itération si­mul­ta­née sur les éléments de deux col­lec­tions de même longueur. L’approche py­tho­nienne utilise la fonction zip(). Celle-ci prend deux col­lec­tions de même longueur et renvoie suc­ces­si­ve­ment 2 tuples :

people = ('Jim', 'Jack', 'John')
ages = (42, 69, 13)
# ascertain both collections are same length
assert len(people) == len(ages)
# iterate over tuples of (person, age)
for person, age in zip(people, ages):
    print(f"{person} is {age} years old")

Créer une variable numérique en boucle avec la fonction range()

Nor­ma­le­ment, les boucles for sont utilisées en Python pour itérer sur les éléments d’une col­lec­tion. L’in­cré­men­ta­tion d’un nombre entier avec une loop for est en Python plutôt un cas spécial. La manière correcte de procéder est de cons­truire un objet range avec la fonction range() et d’itérer sur cet objet :

for counter in range(10):
    print(counter)

Tester si une col­lec­tion contient un élément avec l’opérateur in

Trouver un élément précis dans une col­lec­tion fait partie du ré­per­toire standard d’un pro­gram­meur. Nor­ma­le­ment, une fonction est utilisée pour itérer sur les éléments et vérifier que chaque élément est identique à celui recherché. Si l’élément est trouvé, alors l’itération est in­ter­rom­pue.

En Python, l’opérateur in existe pour ce cas fréquent. L’opérateur vérifie si la col­lec­tion contient l’élément recherché et renvoie une valeur booléenne cor­res­pon­dante :

'a' in 'Python'
'y' in 'Python'

Créer une liste à partir d’une itérable avec la fonction list()

Con­trai­re­ment à de nombreux autres langages, il n’est pas né­ces­saire d’utiliser une loop for en Python pour écrire les lettres d’une chaîne une à une dans une liste. À la place, nous utilisons la fonction list() pour convertir une itérable en une liste d’éléments. Examinons les deux approches à l’aide d’un exemple. Nous itérons sur les lettres d’un mot et les ajoutons à une liste vide :

word = 'Python'
letters = []
for letter in word:
    letters.append(letter)

Nous pouvons nous épargner cet effort. Nous créons di­rec­te­ment la liste avec la fonction list(). Dans le même temps, nous vérifions avec l’ins­truc­tion assert que les deux méthodes donnent le même résultat :

assert list(word) == letters

Voici un autre exemple : nous créons la liste des nombres de zéro à neuf. Un objet range sert de base en tant qu’itérable :

list(range(10))

En plus des listes, il est également possible de créer des ensembles, en anglais « sets », à partir d’une itérable. Par exemple, nous créons un ensemble qui reflète les lettres contenues dans une phrase. Ensuite, nous vérifions avec l’opérateur in que l’ensemble des lettres ne contient pas de 'a' :

alphabet = set('Python is not hyped')
assert 'a' not in alphabet

Remplacer les loops for en Python par des com­pré­hen­sions

Une uti­li­sa­tion fréquente des boucles for en Python consiste à modifier les éléments d’une col­lec­tion. Le cas échéant, nous sou­hai­tons calculer de nouvelles valeurs sur la base d’une col­lec­tion ou filtrer certains éléments selon un modèle. Nous décrivons les dif­fé­rentes étapes en suivant le style de pro­gram­ma­tion impératif :

  1. Itérer sur la col­lec­tion avec la boucle for
  2. Traiter chaque élément
  3. Le cas échéant, regrouper un sous-ensemble d’éléments dans une nouvelle col­lec­tion

Pour de simples mo­di­fi­ca­tions, cela demande beaucoup de travail. Les langages fonc­tion­nels montrent qu’il est possible de faire plus simple. Heu­reu­se­ment, Python connaît le concept des « com­pré­hen­sions ». Les com­pré­hen­sions peuvent remplacer les uti­li­sa­tions simples de la loop for dans Python et sont même parfois plus per­for­mantes.

Une com­pré­hen­sion génère une col­lec­tion, éven­tuel­le­ment modifiée, basée sur une itérable. Une syntaxe concise et ex­pres­sive est utilisée. Con­si­dé­rons la syntaxe générale d’une liste de com­pré­hen­sions. L’ex­pres­sion est écrite entre crochets. Une opération est effectuée sur les éléments d’une col­lec­tion ; chaque élément est copié dans une nouvelle liste :

[ operation(element) for element in collection ]

Il est également possible de filtrer les éléments selon certains modèles, ici avec if-condition :

[ operation(element) for element in collection if condition(element) ]

Con­si­dé­rons main­te­nant un exemple de loop For en Python, qui peut être remplacée par une com­pré­hen­sion. Nous avons une liste de nombres et nous voulons calculer la liste cor­res­pon­dante de carrés :

numbers = [2, 3, 5, 9, 17]

Nous créons une liste vide et la rem­plis­sons avec les carrés dans une boucle for :

squares = []
for number in numbers:
    squares.append(number ** 2)

Plus sim­ple­ment, la liste de carrés peut être exprimée sous forme de com­pré­hen­sion :

squares_comp = [number ** 2 for number in numbers]

Ensuite, nous utilisons l’ins­truc­tion assert pour nous assurer que les deux méthodes donnent le même résultat :

assert squares == squares_comp

Voici un autre exemple : nous voulons extraire des lettres mi­nus­cules d’une chaîne de ca­rac­tères. En entrée, nous créons une liste de lettres de ma­jus­cules et de mi­nus­cules :

word = list("PyThoN")

La manière tra­di­tion­nelle d’extraire les lettres mi­nus­cules consiste à itérer sur la lettre. Nous testons chaque lettre avec la fonction islower() et, si le résultat est positif, nous l’ajoutons à une liste ini­tia­le­ment vide :

lowers = []
for letter in word:
    if letter.islower():
        lowers.append(letter)

Nous pouvons nous passer de cette loop for en Python. Nous utilisons à la place une com­pré­hen­sion qui ne copie que les lettres mi­nus­cules de la liste initiale :

lowers_comp = [ letter for letter in word if letter.islower() ]

Nous vérifions à nouveau l’égalité des deux méthodes à l’aide de l’ins­truc­tion assert :

assert lowers == lowers_comp
Aller au menu principal