W3docs

Python enumerate, zip, map et filter

Apprenez à utiliser enumerate, zip, map et filter en Python, avec des exemples clairs et des modèles pratiques pour un code d'itération plus lisible.

Python fournit quatre fonctions intégrées — enumerate, zip, map et filter — qui remplacent les boucles classiques par une expression unique et lisible. Chacune retourne un itérateur (paresseux, économe en mémoire) et se compose naturellement avec les boucles for et les compréhensions de listes.

Ce chapitre couvre :

  • enumerate() — boucler avec un index automatique
  • zip() — itérer sur deux séquences ou plus en parallèle
  • map() — appliquer une fonction à chaque élément
  • filter() — ne conserver que les éléments qui satisfont un test
  • Combiner ces quatre fonctions dans des cas réels
  • Quand préférer une compréhension de liste à la place

enumerate() — index pendant la boucle

Lorsque vous avez besoin à la fois de la position et de la valeur dans une boucle, l'approche naïve utilise un compteur manuel :

colors = ["red", "green", "blue"]
i = 0
for color in colors:
    print(i, color)
    i += 1

enumerate() fait cela automatiquement. Elle enveloppe n'importe quel itérable et produit des paires (index, valeur) :

colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
    print(i, color)

Résultat :

0 red
1 green
2 blue

Commencer à partir d'un index différent

Passez un argument start pour commencer le comptage à partir de n'importe quel entier :

fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits, start=1):
    print(f"{i}. {fruit}")

Résultat :

1. apple
2. banana
3. cherry

C'est utile lors de la construction de listes numérotées pour l'affichage, où une numérotation commençant à 0 paraît étrange au lecteur.

enumerate() avec une condition

Puisque enumerate() est simplement un itérateur ordinaire, vous pouvez ajouter des tests if dans le corps de la boucle :

scores = [72, 91, 55, 88, 44]
for rank, score in enumerate(scores, start=1):
    if score >= 80:
        print(f"Rank {rank}: score {score} — PASS")

Résultat :

Rank 2: score 91 — PASS
Rank 4: score 88 — PASS

Obtenir uniquement l'index sans enumerate()

Si vous n'avez besoin que d'un index sans autre chose, range(len(seq)) fonctionne — mais dès que vous avez également besoin de la valeur, utilisez enumerate() pour éviter d'écrire seq[i] à répétition.


zip() — itérer sur plusieurs séquences en parallèle

zip() combine deux itérables ou plus en un seul itérateur de tuples, associant les éléments aux positions correspondantes :

names = ["Alice", "Bob", "Charlie"]
scores = [95, 87, 92]

for name, score in zip(names, scores):
    print(f"{name}: {score}")

Résultat :

Alice: 95
Bob: 87
Charlie: 92

zip() avec trois itérables ou plus

first = ["a", "b", "c"]
second = [1, 2, 3]
third = [True, False, True]

for x, y, z in zip(first, second, third):
    print(x, y, z)

Résultat :

a 1 True
b 2 False
c 3 True

Séquences de longueurs inégales

zip() s'arrête à l'itérable le plus court et abandonne silencieusement les éléments restants des séquences plus longues :

short = [1, 2]
long  = [10, 20, 30, 40]

print(list(zip(short, long)))

Résultat :

[(1, 10), (2, 20)]

Les valeurs 30 et 40 de long sont ignorées. Si vous avez besoin de conserver tous les éléments, utilisez itertools.zip_longest de la bibliothèque standard :

from itertools import zip_longest

short = [1, 2]
long  = [10, 20, 30, 40]

print(list(zip_longest(short, long, fillvalue=0)))

Résultat :

[(1, 10), (2, 20), (0, 30), (0, 40)]

Convertir un résultat zippé en liste ou en dictionnaire

zip() retourne un itérateur paresseux. Enveloppez-le dans list() pour matérialiser toutes les paires à la fois, ou passez-le à dict() pour construire un mapping à partir de deux séquences parallèles :

keys   = ["name", "age", "city"]
values = ["Alice", 30, "Paris"]

record = dict(zip(keys, values))
print(record)

Résultat :

{'name': 'Alice', 'age': 30, 'city': 'Paris'}

Dézipper avec zip(*...)

L'astuce de décompression * « inverse » une séquence de tuples en séquences séparées :

pairs = [(1, "a"), (2, "b"), (3, "c")]
numbers, letters = zip(*pairs)

print(numbers)  # (1, 2, 3)
print(letters)  # ('a', 'b', 'c')

map() — appliquer une fonction à chaque élément

map(function, iterable) applique function à chaque élément et retourne un itérateur paresseux de résultats. Elle remplace une boucle for qui construit une nouvelle liste en transformant chaque élément.

numbers = [1, 2, 3, 4, 5]
squares = map(lambda x: x ** 2, numbers)
print(list(squares))

Résultat :

[1, 4, 9, 16, 25]

map() avec une fonction nommée

Vous pouvez passer n'importe quel callable — une fonction intégrée, une fonction définie avec def, ou une lambda :

words = ["  hello  ", "  world  ", "  python  "]
stripped = list(map(str.strip, words))
print(stripped)

Résultat :

['hello', 'world', 'python']

Ici str.strip est passé en référence (sans parenthèses). map() appelle str.strip(word) pour chaque élément.

map() sur plusieurs itérables

Passez des itérables supplémentaires pour mapper une fonction qui prend deux arguments ou plus. map() parcourt alors tous les itérables en parallèle (comme zip(), il s'arrête au plus court) :

a = [1, 2, 3]
b = [10, 20, 30]
totals = list(map(lambda x, y: x + y, a, b))
print(totals)

Résultat :

[11, 22, 33]

map() vs compréhension de liste

Les deux approches sont valides. La règle générale :

SituationPréférer
Appliquer une fonction nommée existantemap() — plus court, pas besoin de lambda
Écrire une expression en ligneCompréhension de liste — plus lisible
Plusieurs entrées en parallèlemap() avec plusieurs itérables

Formes équivalentes :

# map() with a named function
result = list(map(str.upper, ["a", "b", "c"]))

# list comprehension — same result
result = [s.upper() for s in ["a", "b", "c"]]

filter() — ne conserver que les éléments correspondant à une condition

filter(function, iterable) conserve les éléments pour lesquels function retourne une valeur vraie. Elle retourne un itérateur paresseux.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens))

Résultat :

[2, 4, 6, 8, 10]

filter() avec une fonction nommée

def is_positive(n):
    return n > 0

values = [-3, -1, 0, 4, 7, -2]
positives = list(filter(is_positive, values))
print(positives)

Résultat :

[4, 7]

filter(None, iterable) — supprimer les valeurs fausses

Passer None comme fonction ne conserve que les éléments vrais. C'est un moyen rapide de supprimer les chaînes vides, les zéros et les valeurs None :

mixed = [0, "hello", "", None, 42, False, "world"]
truthy = list(filter(None, mixed))
print(truthy)

Résultat :

['hello', 42, 'world']

filter() vs compréhension de liste

filter() et une compréhension de liste conditionnelle font le même travail :

numbers = range(1, 11)

# filter()
evens_f = list(filter(lambda x: x % 2 == 0, numbers))

# list comprehension — equivalent
evens_c = [x for x in numbers if x % 2 == 0]

print(evens_f)  # [2, 4, 6, 8, 10]
print(evens_c)  # [2, 4, 6, 8, 10]

Préférez une compréhension de liste lorsque la condition est écrite en ligne ; préférez filter() lorsque vous disposez déjà d'une fonction prédicat bien nommée.


Combiner enumerate, zip, map et filter

Ces quatre fonctions se composent naturellement. Voici un exemple réaliste : vous avez deux listes parallèles de noms d'élèves et de notes brutes ; vous souhaitez afficher un rapport numéroté qui n'inclut que les élèves ayant réussi (note >= 60), avec les notes converties en lettres.

def letter_grade(score):
    if score >= 90:
        return "A"
    elif score >= 80:
        return "B"
    elif score >= 70:
        return "C"
    elif score >= 60:
        return "D"
    return "F"

names  = ["Alice", "Bob", "Carol", "Dave", "Eve"]
scores = [85, 52, 91, 67, 48]

# Step 1: pair names with scores
pairs = zip(names, scores)

# Step 2: keep only passing students
passing = filter(lambda pair: pair[1] >= 60, pairs)

# Step 3: convert scores to letter grades
graded = map(lambda pair: (pair[0], letter_grade(pair[1])), passing)

# Step 4: number the results
for rank, (name, grade) in enumerate(graded, start=1):
    print(f"{rank}. {name}: {grade}")

Résultat :

1. Alice: B
2. Carol: A
3. Dave: D

Chaque étape produit un itérateur ; rien n'est matérialisé dans une liste jusqu'à ce que la boucle for le consomme. Cela maintient une utilisation mémoire constante quelle que soit la taille de l'entrée.


Pièges courants

Les itérateurs sont épuisés après un seul passage

map(), filter() et zip() retournent tous des itérateurs, pas des listes. Une fois qu'un itérateur est consommé, il est vide :

squares = map(lambda x: x ** 2, [1, 2, 3])
print(list(squares))  # [1, 4, 9]
print(list(squares))  # [] — already exhausted

Enveloppez dans list() dès le départ si vous avez besoin d'itérer plus d'une fois.

zip() abandonne silencieusement les éléments en fin de séquence

Lorsque les séquences d'entrée ont des longueurs différentes, zip() supprime les éléments supplémentaires sans avertissement. Vérifiez toujours les longueurs explicitement si cela est important, ou utilisez itertools.zip_longest.

enumerate() ne modifie pas l'itérable

enumerate() enveloppe l'itérable d'origine ; il ne le copie pas. Modifier la liste sous-jacente pendant l'itération peut produire des résultats inattendus — la même précaution qui s'applique aux boucles for ordinaires.


Référence rapide

FonctionSignatureCe qu'elle retourne
enumerateenumerate(iterable, start=0)Itérateur de tuples (index, value)
zipzip(*iterables)Itérateur de tuples, un élément de chaque itérable par tuple
mapmap(function, *iterables)Itérateur de function appliqué à chaque élément
filterfilter(function, iterable)Itérateur d'éléments où function retourne True

Les quatre sont paresseuses : elles produisent les valeurs à la demande plutôt que de construire une liste complète à l'avance.


Pratique

Pratique
What does enumerate(items, start=1) do when used in a for loop?
What does enumerate(items, start=1) do when used in a for loop?
Pratique
What happens when you pass sequences of different lengths to zip()?
What happens when you pass sequences of different lengths to zip()?
Pratique
Which statement about map() is correct?
Which statement about map() is correct?
Pratique
What does filter(None, iterable) do?
What does filter(None, iterable) do?
Was this page helpful?