Compréhensions Python : compréhensions de liste, de dictionnaire et d’ensemble

Remplacez la plupart de vos boucles par une seule ligne lisible qui construit la collection sur place.

Apprenez les compréhensions Python — de liste, de dictionnaire et d’ensemble — en transformant une boucle for en une seule expression. Couvre le filtrage avec if, les valeurs conditionnelles, les compréhensions imbriquées, et les cas où une expression génératrice (ou une simple boucle) est le meilleur choix. Chaque bloc s’exécute et affiche son résultat.

Date de publication

26 juin 2026

Modifié

7 juillet 2026

AstucePoints clés
  • Une compréhension est une boucle qui construit une collection, écrite comme une seule expression. [f(x) for x in items] fait ce qu’une boucle for avec .append() fait — en une seule ligne lisible.
  • La forme reste la même d’un type à l’autre. [...] construit une liste, {k: v ...} un dictionnaire, {...} un ensemble. Apprenez la forme liste et les autres suivent.
  • Ajoutez if à la fin pour filtrer ; placez if/else avant le for pour choisir une valeur. Deux tâches différentes, deux positions différentes — les confondre est le bug classique du débutant.
  • Remplacez les crochets par des parenthèses pour obtenir un générateur qui produit un élément à la fois au lieu de construire toute la liste en mémoire — essentiel pour les données volumineuses ou en flux.
  • Imbriquez avec parcimonie. Un niveau se lit bien ; deux niveaux se lisent généralement mieux sous forme de vraie boucle for. La clarté l’emporte sur l’astuce.
  • Une simple boucle gagne quand le corps a des effets de bord ou plusieurs instructions. Les compréhensions servent à construire une collection, pas à faire un travail.

Introduction

Vous recourez constamment à une boucle : parcourir une liste, transformer chaque élément, collecter les résultats. En Python, ce motif — démarrer une liste vide, boucler, .append() — est si courant que le langage vous offre un raccourci en une ligne pour cela : la compréhension.

Une compréhension dit « construis cette collection à partir de celle-là » en une seule expression. Elle se lit presque comme la phrase que vous diriez à voix haute — « le carré de chaque nombre dans nums » devient [n**2 for n in nums]. Une fois le déclic fait, vous écrirez moins de boucles, avec moins de code répétitif à mal écrire (pas de liste vide à oublier, pas d’index à mal gérer).

Cette leçon montre toujours la boucle d’abord, puis la compréhension qui la remplace, pour que vous voyiez la correspondance exacte. Ensuite elle couvre le filtrage, les compréhensions de dictionnaire et d’ensemble, les générateurs (le cousin économe en mémoire), et — tout aussi important — quand ne pas utiliser de compréhension du tout.

Chaque résultat sur cette page est réel — et vous pouvez l’exécuter vous-même sans rien installer : cliquez sur Try ▸ sous n’importe quel bloc pour l’exécuter en direct dans votre navigateur (Python démarre au premier Run, puis c’est instantané).

D’une boucle à une compréhension de liste

Voici le motif dans sa forme la plus simple. Nous voulons les carrés de quelques nombres. La méthode avec boucle : créer une liste vide, parcourir l’entrée, ajouter chaque valeur transformée.

nums = [1, 2, 3, 4, 5]

squares = []
for n in nums:
    squares.append(n ** 2)

squares
[1, 4, 9, 16, 25]

Trois lignes de gestion — la liste vide, l’en-tête de boucle, l’ajout — pour exprimer une seule idée : mettre au carré chaque nombre. La compréhension replie ces trois lignes en une seule expression. Lisez-la de droite à gauche au début : for n in nums est la boucle, n ** 2 est ce que vous collectez.

nums = [1, 2, 3, 4, 5]

squares = [n ** 2 for n in nums]
squares
[1, 4, 9, 16, 25]

Même résultat, une seule ligne, et l’intention est en surface. La forme générale est :

[ EXPRESSION for ITEM in ITERABLE ]

EXPRESSION est ce que chaque élément de sortie doit être ; ITEM est la variable de boucle ; ITERABLE est ce que vous parcourez. Tout ce que vous pouvez parcourir avec for fonctionne ici — une liste, une chaîne, un range, un fichier, les clés d’un dictionnaire.

# Uppercase each word — iterate a list of strings
words = ["data", "novia", "python"]
[w.upper() for w in words]
['DATA', 'NOVIA', 'PYTHON']

L’expression peut être n’importe quelle fonction de l’élément, y compris un appel de méthode comme w.upper() ci-dessus.

Filtrage : ajoutez if à la fin

Souvent vous ne voulez pas tous les éléments — seulement ceux qui passent un test. La boucle ajoute un if à l’intérieur du corps. Ici nous gardons uniquement les nombres pairs.

nums = range(1, 11)

evens = []
for n in nums:
    if n % 2 == 0:
        evens.append(n)

evens
[2, 4, 6, 8, 10]

Dans une compréhension, le filtre va à la fin, après le for. Lisez-le comme « n pour chaque n dans nums, si n est pair » :

evens = [n for n in range(1, 11) if n % 2 == 0]
evens
[2, 4, 6, 8, 10]

La forme est maintenant :

[ EXPRESSION for ITEM in ITERABLE if CONDITION ]

Un if final décide si un élément apparaît ou non. Les éléments qui échouent au test sont simplement ignorés — la sortie est plus courte que l’entrée. Vous pouvez combiner le filtrage avec une transformation : garder les pairs et les mettre au carré.

[n ** 2 for n in range(1, 11) if n % 2 == 0]
[4, 16, 36, 64, 100]

Valeurs conditionnelles : if/else avant le for

Il y a un deuxième usage, différent, de if — choisir quelle valeur produire, tout en gardant chaque élément. C’est une expression conditionnelle (A if test else B), et elle va dans l’emplacement de l’expression, avant le for. Ici nous étiquetons chaque nombre « even » ou « odd » — la sortie a la même longueur que l’entrée.

labels = []
for n in range(1, 6):
    labels.append("even" if n % 2 == 0 else "odd")

labels
['odd', 'even', 'odd', 'even', 'odd']

Sous forme de compréhension, le "even" if ... else "odd" complet se place là où va l’expression :

["even" if n % 2 == 0 else "odd" for n in range(1, 6)]
['odd', 'even', 'odd', 'even', 'odd']

Remarquez les deux positions et ce qu’elles signifient :

  • Filtrerif à la fin, sans else : élimine des éléments. « …s’il est pair. »
  • Choisir une valeurif/else au début : garde chaque élément, choisit sa valeur. « …pair ou impair. »

Si Python se plaint de la syntaxe d’un conditionnel dans une compréhension, c’est presque toujours parce que le if est au mauvais endroit pour ce que vous vouliez dire. Filtrez à la fin ; choisissez au début.

Compréhensions de dictionnaire

La même idée construit un dictionnaire — vous produisez simplement une paire key: value au lieu d’une valeur unique, et vous l’entourez de {}. La version avec boucle construit un dictionnaire vide et y affecte les valeurs.

words = ["data", "novia", "python"]

lengths = {}
for w in words:
    lengths[w] = len(w)

lengths
{'data': 4, 'novia': 5, 'python': 6}

La compréhension énonce la paire directement : w: len(w) for each w.

{w: len(w) for w in words}
{'data': 4, 'novia': 5, 'python': 6}

La forme reflète celle de la liste, avec une expression key: value :

{ KEY: VALUE for ITEM in ITERABLE }

Un motif courant consiste à transformer deux listes parallèles en un dictionnaire, en les appariant avec zip() :

names = ["Ada", "Linus", "Grace"]
roles = ["analyst", "engineer", "admiral"]

{name: role for name, role in zip(names, roles)}
{'Ada': 'analyst', 'Linus': 'engineer', 'Grace': 'admiral'}

Le filtrage fonctionne exactement comme avant — un if final. Ici nous gardons uniquement les mots longs :

{w: len(w) for w in words if len(w) > 4}
{'novia': 5, 'python': 6}

Compréhensions d’ensemble

Utilisez {} avec une seule expression (sans deux-points) pour construire un ensemble — les résultats uniques, sans doublons, sans ordre. C’est la façon naturelle de collecter des valeurs distinctes. La version avec boucle utilise un ensemble et .add().

text = "mississippi"

# Loop: collect the distinct letters
seen = set()
for ch in text:
    seen.add(ch)

seen
{'i', 'm', 'p', 's'}

La compréhension tient en une ligne, et la déduplication est automatique — "mississippi" a de nombreuses répétitions mais l’ensemble ne garde chaque lettre qu’une fois.

{ch for ch in "mississippi"}
{'i', 'm', 'p', 's'}

Une compréhension d’ensemble brille quand vous transformez et voulez l’unicité en une seule étape — ici, les longueurs de mots distinctes :

words = ["data", "novia", "code", "r", "python"]
{len(w) for w in words}
{1, 4, 5, 6}

Quatre mots ont une longueur de 4 ou 6, mais l’ensemble ne rapporte chaque longueur distincte qu’une fois.

Compréhensions imbriquées (à utiliser avec précaution)

Vous pouvez boucler deux fois dans une seule compréhension. Les deux clauses for se lisent de gauche à droite, de l’extérieur vers l’intérieur — le même ordre que si vous imbriquiez les boucles. Ici nous aplatissons une liste de lignes en une seule liste.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# Loop version
flat = []
for row in matrix:
    for value in row:
        flat.append(value)

flat
[1, 2, 3, 4, 5, 6, 7, 8, 9]

La compréhension garde le même ordre for row ... for value :

[value for row in matrix for value in row]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Celle-là se lit bien. Mais l’imbrication vous pousse vers des lignes que personne ne pourra analyser une semaine plus tard. Une règle empirique : si vous avez besoin de plus d’un for, ou d’un for plus un if délicat, arrêtez-vous et demandez-vous si une simple boucle se lit mieux. C’est généralement le cas — la boucle a la place de nommer les étapes intermédiaires et de respirer. Les compréhensions sont un outil de clarté ; dès qu’elles nuisent à la lisibilité, elles ont cessé de faire leur travail.

Expressions génératrices : même syntaxe, moins de mémoire

Une compréhension de liste construit la liste entière en mémoire d’un seul coup. Pour quelques milliers d’éléments, ce n’est rien. Pour des millions — ou un flux sans fin — c’est un problème. Remplacez les crochets par des parenthèses et vous obtenez une expression génératrice : elle produit les éléments un à la fois, à la demande, ne gardant que l’élément courant.

nums = range(1, 1_000_001)  # one million numbers

# List comprehension — builds a 1,000,000-element list in memory
squares_list = [n ** 2 for n in nums]

# Generator expression — builds nothing yet; yields on demand
squares_gen = (n ** 2 for n in nums)

print(type(squares_list), "len:", len(squares_list))
print(type(squares_gen))
<class 'list'> len: 1000000
<class 'generator'>

La liste est entièrement matérialisée ; le générateur n’est qu’une recette — aucune liste d’un million d’éléments n’existe tant que quelque chose ne demande pas les valeurs. C’est tout l’intérêt : quand vous avez seulement besoin de consommer les valeurs une fois (souvent pour alimenter un agrégat), le générateur n’alloue jamais la liste.

# sum() pulls values from the generator one at a time — no giant list built
total = sum(n ** 2 for n in range(1, 1_000_001))
total
333333833333500000

Quand vous passez une expression génératrice comme unique argument à une fonction comme sum(), max(), ou any(), vous pouvez même supprimer les parenthèses supplémentaires — sum(n ** 2 for n in ...) se lit clairement.

Le compromis : un générateur est à usage unique et non indexable. Vous pouvez le parcourir une fois ; il n’y a pas de gen[3] ni de len(gen). Si vous avez besoin d’un accès aléatoire, du décompte, ou de boucler plus d’une fois, construisez une liste. Si vous parcourez des valeurs une seule fois — surtout des grandes — utilisez un générateur.

Quand une simple boucle est plus claire

Les compréhensions servent à construire une collection. Quand ce n’est pas ce que vous faites, une boucle est le choix honnête. Recourez à une boucle for classique quand :

  • Le corps a des effets de bord — afficher, écrire dans un fichier, mettre à jour une base de données, journaliser. Une compréhension construite uniquement pour ses effets de bord ([print(x) for x in items]) construit une liste jetable de None et masque l’intention. Bouclez simplement.
  • Le corps a besoin de plusieurs instructions — try/except, plusieurs affectations, une branche qui fait un vrai travail. Une compréhension est une seule expression ; y entasser de la logique la rend illisible.
  • Les itérations dépendent les unes des autres — un total cumulé qui alimente l’étape suivante, un break anticipé, l’accumulation d’un état. Les compréhensions ne peuvent pas faire break et n’ont pas de place pour des variables intermédiaires.

Voici le cas des effets de bord bien fait — une boucle, parce que nous faisons quelque chose par élément, sans collecter de résultats :

records = [("Ada", 95), ("Linus", 60), ("Grace", 88)]

for name, score in records:
    status = "pass" if score >= 70 else "review"
    print(f"{name}: {score} -> {status}")
Ada: 95 -> pass
Linus: 60 -> review
Grace: 88 -> pass

C’est plus clair que n’importe quelle ligne unique. Le savoir-faire n’est pas d’utiliser des compréhensions partout — c’est de connaître la seule tâche pour laquelle elles excellent et d’utiliser une boucle pour le reste.

🟢 Avec un agent IA

Collez une boucle for que vous avez écrite et demandez à Prova « réécris ceci sous forme de compréhension » — elle replie la liste vide, la boucle et le .append() en une seule expression, filtrant à la fin ou choisissant une valeur au début selon ce que votre code veut dire. Parce que le runtime est juste ici, vous exécutez les deux et vérifiez qu’ils produisent le même résultat avec loop_result == comp_result, de sorte que vous faites confiance à la réécriture plutôt que d’accepter une réponse plausible sur parole. The runtime is the judge. Demander à Prova →

Essayez en direct

Les blocs ci-dessus ont été exécutés au moment de la génération. Modifiez celui-ci et appuyez sur Run pour essayer les compréhensions par vous-même — il s’exécute dans votre navigateur via Pyodide (sans installation). Ou cliquez sur Try ▸ sous n’importe quel bloc ci-dessus pour y déposer son code.

Problèmes courants

Une compréhension de liste sur des données volumineuses dévore la mémoire. [expensive(x) for x in millions] alloue la liste entière avant que vous ne touchiez un seul élément. Si vous ne parcourez les résultats qu’une fois — pour sum(), max(), écrire dans un fichier, ou alimenter une autre boucle — utilisez une expression génératrice (parenthèses) pour que les valeurs circulent une à la fois et que rien ne soit stocké. Revenez à une liste seulement quand vous avez besoin de l’indexation, de la longueur, ou de plus d’un passage.

Le if est au mauvais endroit. Un if final (après le for) filtre — il élimine des éléments. Un if/else dans l’emplacement de l’expression (avant le for) choisit une valeur et garde chaque élément. [x for x in xs if x > 0] garde les positifs ; [x if x > 0 else 0 for x in xs] remplace les négatifs par 0. Un simple if/else placé à la fin est une SyntaxError ; un filtre placé au début aussi. Décidez d’abord : filtrer ou choisir ?

S’attendre à ce qu’une variable de boucle fuie à l’extérieur. En Python 3, la variable de compréhension est limitée à la compréhension — après [n for n in range(5)], il ne reste aucun n dans le code environnant (contrairement à une simple boucle for, dont la variable persiste). Ne comptez pas sur la lecture de la « dernière valeur » de la variable d’une compréhension ; elle n’est pas là.

Questions fréquentes

Évitez la compréhension quand vous ne construisez pas une collection. Si le corps de la boucle a des effets de bord (afficher, écrire des fichiers, journaliser), a besoin de plusieurs instructions (un try/except, plusieurs affectations), utilise break/continue, ou que chaque itération dépend de la précédente (un total cumulé), une simple boucle for est plus claire et l’outil adapté. Les compréhensions servent à transformer une collection en une autre — quand ce n’est pas l’objectif, ne forcez pas.

Une compréhension de liste ([...]) construit la liste entière en mémoire d’un seul coup ; une expression génératrice ((...)) ne construit rien au départ et produit les valeurs une à la fois au fur et à mesure que vous itérez. La liste est réutilisable et indexable (xs[3], len(xs)) ; le générateur est à usage unique, non indexable, et n’utilise presque pas de mémoire. Utilisez une liste quand vous avez besoin d’un accès aléatoire, du décompte, ou de plusieurs passages ; utilisez un générateur pour des données volumineuses ou en flux que vous parcourez une fois — par exemple sum(x**2 for x in big).

Il y en a deux sortes. Pour filtrer (éliminer certains éléments), placez if CONDITION à la fin : [x for x in xs if x > 0]. Pour choisir une valeur tout en gardant chaque élément, placez une expression conditionnelle dans l’emplacement de début : [x if x > 0 else 0 for x in xs]. La position est la règle — un if final filtre ; un if/else en tête choisit une valeur.

Oui — même syntaxe, crochets différents. {k: v for ...} (avec un deux-points) construit un dictionnaire ; {expr for ...} (sans deux-points) construit un ensemble de résultats uniques ; [expr for ...] construit une liste. Ainsi {w: len(w) for w in words} crée un dictionnaire des longueurs de mots, et {len(w) for w in words} crée l’ensemble des longueurs distinctes.

Généralement un peu — une compréhension évite la recherche répétée de l’attribut .append() et exécute davantage de son travail en bytecode optimisé, donc elle est souvent modestement plus rapide que la boucle explicite équivalente. Mais l’écart est faible ; choisissez une compréhension pour la lisibilité, pas pour la vitesse brute. Pour un travail numérique vraiment lourd, une bibliothèque vectorisée comme NumPy bat les deux.

Testez vos connaissances

Travaillez chaque tâche dans la cellule Essayez en direct ci-dessus — modifiez et exécutez.

On vous donne ce code. Réécrivez chaque bloc sous forme de compréhension appropriée (liste, dictionnaire ou ensemble).

nums = [3, -1, 4, -1, 5, -9, 2, 6]

# 1. The squares of only the positive numbers (a list)
pos_squares = []
for n in nums:
    if n > 0:
        pos_squares.append(n ** 2)

# 2. A label per number: "pos" or "neg", keeping all of them (a list)
labels = []
for n in nums:
    labels.append("pos" if n > 0 else "neg")

# 3. The distinct absolute values (a set)
abs_vals = set()
for n in nums:
    abs_vals.add(abs(n))

Le bloc 1 filtre, donc if va à la fin. Le bloc 2 choisit une valeur pour chaque élément, donc le if/else va dans l’emplacement de l’expression, avant le for. Le bloc 3 veut l’unicité, donc utilisez une compréhension d’ensemble {...}.

nums = [3, -1, 4, -1, 5, -9, 2, 6]

pos_squares = [n ** 2 for n in nums if n > 0]
labels      = ["pos" if n > 0 else "neg" for n in nums]
abs_vals    = {abs(n) for n in nums}

Le if du bloc 1 filtre à la fin ; le if/else du bloc 2 choisit une valeur au début ; le {...} du bloc 3 réduit les doublons (-1 apparaît deux fois mais 1 n’arrive qu’une fois dans l’ensemble).

Vous devez calculer la somme de n ** 2 pour n de 1 à dix millions, et vous n’utilisez le résultat qu’une fois. Devriez-vous écrire sum([n ** 2 for n in range(1, 10_000_001)]) ou sum(n ** 2 for n in range(1, 10_000_001)), et pourquoi ?

Une version construit une liste de dix millions d’éléments en mémoire avant de sommer. L’autre produit les valeurs une à la fois. Vous consommez les valeurs exactement une fois.

Utilisez l’expression génératrice : sum(n ** 2 for n in range(1, 10_000_001)). La forme avec compréhension de liste construit une liste de dix millions d’éléments en mémoire juste pour la jeter après la somme. Le générateur produit chaque carré à la demande, donc sum() les additionne un à la fois et rien n’est stocké. Comme vous ne parcourez les valeurs qu’une fois, vous n’avez jamais besoin de la liste.

Vous voulez uniquement les nombres pairs de nums. Quelle compréhension est correcte ?

A. [n if n % 2 == 0 else None for n in nums] — une valeur conditionnelle B. [n for n in nums if n % 2 == 0] — un filtre final C. {n: n % 2 == 0 for n in nums} — un dictionnaire

B. Un if final filtre — il garde uniquement les éléments qui passent, donc vous obtenez juste les pairs. A garde chaque élément, remplaçant les impairs par None (une valeur conditionnelle, pas un filtre). C construit un dictionnaire associant chaque nombre à True/False, pas une liste filtrée. Pour éliminer des éléments, placez if à la fin sans else.

Conclusion

Une compréhension est une boucle for qui construit une collection, écrite comme une seule expression — [f(x) for x in items], avec {k: v ...} pour les dictionnaires et {...} pour les ensembles. Ajoutez un if final pour filtrer, un if/else en tête pour choisir des valeurs, et passez aux parenthèses pour un générateur quand la mémoire compte. Gardez-les peu profondes et utilisez-les pour construire des collections ; quand le corps fait un vrai travail ou plusieurs étapes, une simple boucle est le choix le plus clair.

À voir aussi : DataFrames pandas — mettez la même idée de transformation-sur-une-collection au travail sur de vraies données tabulaires. · La famille apply de R — la même idée « faire ceci à chaque élément », à la manière de R.

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Compréhensions Python : compréhensions de liste, de
    dictionnaire et d’ensemble},
  date = {2026-06-26},
  url = {https://www.datanovia.com/learn/programming/python-foundations/comprehensions},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Compréhensions Python : compréhensions de liste, de dictionnaire et d’ensemble.” 2026. June 26. https://www.datanovia.com/learn/programming/python-foundations/comprehensions.