Les compréhensions de listes sont l'une des fonctionnalités les plus puissantes et élégantes de Python. Elles permettent d'écrire en une seule ligne ce qui nécessiterait normalement plusieurs lignes de code avec des boucles. Dans cet article, nous allons explorer en profondeur les compréhensions de listes, comprendre comment elles fonctionnent vraiment, et voir quand et comment les utiliser efficacement.
Qu'est-ce qu'une compréhension de liste ?
Le problème de départ
Imaginons que vous voulez créer une liste des carrés des nombres de 0 à 9. La façon traditionnelle serait :
# Méthode classique avec une boucle for
carres = []
for i in range(10):
carres.append(i ** 2)
print(carres) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Ça fonctionne, mais c'est un peu verbeux. On doit :
-
Créer une liste vide
-
Faire une boucle
-
Ajouter chaque élément avec
append()
La solution élégante : la compréhension de liste
Voici la même chose avec une compréhension de liste :
# Avec une compréhension de liste
carres = [i ** 2 for i in range(10)]
print(carres) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Une seule ligne ! C'est plus lisible, plus concis, et même plus rapide à l'exécution.
La syntaxe générale
La structure de base d'une compréhension de liste est :
[expression for element in iterable]
Décortiquons cette syntaxe :
-
expression: ce qu'on veut faire avec chaque élément -
element: la variable qui représente chaque élément -
iterable: la source de données (liste, range, chaîne, etc.)
Exemples de base pour bien comprendre
Exemple 1 : Transformer chaque élément
# Créer une liste de prénoms en majuscules
prenoms = ["alice", "bob", "charlie", "diana"]
# Version avec boucle
prenoms_maj = []
for prenom in prenoms:
prenoms_maj.append(prenom.upper())
# Version avec compréhension de liste
prenoms_maj = [prenom.upper() for prenom in prenoms]
print(prenoms_maj) # ['ALICE', 'BOB', 'CHARLIE', 'DIANA']
Exemple 2 : Opérations mathématiques
# Convertir des températures de Celsius vers Fahrenheit
celsius = [0, 10, 20, 30, 40]
fahrenheit = [(temp * 9/5) + 32 for temp in celsius]
print(fahrenheit) # [32.0, 50.0, 68.0, 86.0, 104.0]
Exemple 3 : Extraire des informations
# Extraire les longueurs de mots
mots = ["Python", "est", "génial"]
longueurs = [len(mot) for mot in mots]
print(longueurs) # [6, 3, 6]
Ajouter des conditions : filtrer les données
La vraie puissance des compréhensions de liste apparaît quand on ajoute des conditions pour filtrer les données.
Syntaxe avec condition
[expression for element in iterable if condition]
La condition agit comme un filtre : seuls les éléments qui satisfont la condition sont inclus dans la nouvelle liste.
Exemple 1 : Filtrer les nombres pairs
nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Version avec boucle
pairs = []
for nombre in nombres:
if nombre % 2 == 0:
pairs.append(nombre)
# Version avec compréhension de liste
pairs = [nombre for nombre in nombres if nombre % 2 == 0]
print(pairs) # [2, 4, 6, 8, 10]
Exemple 2 : Filtrer et transformer
# Obtenir les carrés des nombres impairs uniquement
nombres = range(10)
carres_impairs = [n ** 2 for n in nombres if n % 2 != 0]
print(carres_impairs) # [1, 9, 25, 49, 81]
Exemple 3 : Filtrer des chaînes de caractères
# Garder uniquement les mots de plus de 4 lettres
phrase = "Python est un langage de programmation puissant"
mots = phrase.split()
mots_longs = [mot for mot in mots if len(mot) > 4]
print(mots_longs) # ['Python', 'langage', 'programmation', 'puissant']
Application pratique : traiter des données de films
Reprenons notre exemple de films et voyons comment les compréhensions de listes simplifient le code.
Les données
films = [
{"titre": "Inception", "realisateur": "Nolan", "annee": 2010, "budget": 160000000, "note": 8.8},
{"titre": "Pulp Fiction", "realisateur": "Tarantino", "annee": 1994, "budget": 8000000, "note": 8.9},
{"titre": "Le Parrain", "realisateur": "Coppola", "annee": 1972, "budget": 6000000, "note": 9.2},
{"titre": "Parasite", "realisateur": "Bong", "annee": 2019, "budget": 11400000, "note": 8.5},
{"titre": "Interstellar", "realisateur": "Nolan", "annee": 2014, "budget": 165000000, "note": 8.6},
]
Extraire des informations spécifiques
# Obtenir tous les titres
titres = [film["titre"] for film in films]
print(titres)
# ['Inception', 'Pulp Fiction', 'Le Parrain', 'Parasite', 'Interstellar']
# Obtenir tous les budgets
budgets = [film["budget"] for film in films]
print(f"Budget moyen : {sum(budgets) / len(budgets):,.0f}€")
# Budget moyen : 70,080,000€
Filtrer selon des critères
# Films à petit budget (< 50 millions)
petits_budgets = [film["titre"] for film in films if film["budget"] < 50000000]
print("Films à petit budget :", petits_budgets)
# ['Pulp Fiction', 'Le Parrain', 'Parasite']
# Films récents (après 2010)
films_recents = [film["titre"] for film in films if film["annee"] > 2010]
print("Films récents :", films_recents)
# ['Interstellar', 'Parasite']
# Films très bien notés (note > 8.7)
excellents = [film["titre"] for film in films if film["note"] > 8.7]
print("Films excellents :", excellents)
# ['Pulp Fiction', 'Le Parrain', 'Inception']
Combiner plusieurs critères
# Films de Nolan avec une bonne note
nolan_top = [
film["titre"]
for film in films
if film["realisateur"] == "Nolan" and film["note"] > 8.5
]
print("Top films de Nolan :", nolan_top)
# ['Inception', 'Interstellar']
# Films récents à petit budget
recents_petits = [
f"{film['titre']} ({film['annee']})"
for film in films
if film["annee"] > 2010 and film["budget"] < 50000000
]
print("Films récents à petit budget :", recents_petits)
# ['Parasite (2019)']
Créer des structures de données complexes
# Créer une liste de tuples (titre, note)
titres_notes = [(film["titre"], film["note"]) for film in films]
print(titres_notes)
# [('Inception', 8.8), ('Pulp Fiction', 8.9), ...]
# Créer un résumé formaté
resumes = [
f"{film['titre']} de {film['realisateur']} ({film['annee']}) - Note: {film['note']}/10"
for film in films
]
for resume in resumes:
print(resume)
Résultat :
Inception de Nolan (2010) - Note: 8.8/10
Pulp Fiction de Tarantino (1994) - Note: 8.9/10
Le Parrain de Coppola (1972) - Note: 9.2/10
Parasite de Bong (2019) - Note: 8.5/10
Interstellar de Nolan (2014) - Note: 8.6/10
Compréhensions imbriquées : aller plus loin
On peut imbriquer des compréhensions de listes pour traiter des structures de données plus complexes.
Exemple 1 : Aplatir une liste de listes
# Liste de listes
matrice = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Aplatir en une seule liste
aplati = [nombre for ligne in matrice for nombre in ligne]
print(aplati) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
Comment lire cette syntaxe ?
C'est comme deux boucles imbriquées :
# Équivalent avec des boucles
aplati = []
for ligne in matrice:
for nombre in ligne:
aplati.append(nombre)
Dans la compréhension de liste, on lit de gauche à droite comme on écrirait les boucles.
Exemple 2 : Créer une matrice
# Créer une matrice 3x3 de zéros
matrice = [[0 for _ in range(3)] for _ in range(3)]
print(matrice)
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# Créer une table de multiplication
table = [[i * j for j in range(1, 6)] for i in range(1, 6)]
for ligne in table:
print(ligne)
Résultat :
[1, 2, 3, 4, 5]
[2, 4, 6, 8, 10]
[3, 6, 9, 12, 15]
[4, 8, 12, 16, 20]
[5, 10, 15, 20, 25]
Exemple 3 : Combinaisons de listes
# Créer toutes les paires possibles
couleurs = ["rouge", "vert", "bleu"]
tailles = ["S", "M", "L"]
produits = [
f"{couleur}-{taille}"
for couleur in couleurs
for taille in tailles
]
print(produits)
# ['rouge-S', 'rouge-M', 'rouge-L', 'vert-S', 'vert-M',
# 'vert-L', 'bleu-S', 'bleu-M', 'bleu-L']
Compréhensions avec if-else : logique conditionnelle
Parfois, on veut appliquer une transformation différente selon une condition, sans filtrer les éléments.
Syntaxe avec if-else
[expression_if_true if condition else expression_if_false for element in iterable]
Attention : l'ordre est différent ! Le if-else vient avant le for.
Exemple 1 : Catégoriser des nombres
nombres = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Mettre "pair" ou "impair"
categories = ["pair" if n % 2 == 0 else "impair" for n in nombres]
print(categories)
# ['impair', 'pair', 'impair', 'pair', 'impair', 'pair',
# 'impair', 'pair', 'impair', 'pair']
Exemple 2 : Normaliser des données
# Remplacer les valeurs négatives par 0
temperatures = [20, -5, 15, -10, 25, 0, -3]
temperatures_positives = [temp if temp >= 0 else 0 for temp in temperatures]
print(temperatures_positives) # [20, 0, 15, 0, 25, 0, 0]
Exemple 3 : Appliquer une remise
# 20% de réduction sur les articles > 50€
prix = [30, 60, 25, 80, 45, 100]
prix_finaux = [p * 0.8 if p > 50 else p for p in prix]
print(prix_finaux) # [30, 48.0, 25, 64.0, 45, 80.0]
Combiner filtrage et transformation conditionnelle
On peut même combiner les deux syntaxes :
# Garder les nombres pairs, et doubler ceux qui sont > 5
nombres = range(1, 11)
resultat = [
n * 2 if n > 5 else n
for n in nombres
if n % 2 == 0
]
print(resultat) # [2, 4, 12, 16, 20]
Explication :
-
On filtre d'abord les pairs avec
if n % 2 == 0 -
Parmi les pairs, ceux > 5 sont doublés, les autres gardés tels quels
Compréhensions de dictionnaires et d'ensembles
Python offre aussi des compréhensions pour créer des dictionnaires et des ensembles.
Compréhensions de dictionnaires
Syntaxe :
{cle: valeur for element in iterable}
Exemples :
# Créer un dictionnaire nombre -> carré
carres = {n: n**2 for n in range(1, 6)}
print(carres) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Inverser un dictionnaire
original = {"a": 1, "b": 2, "c": 3}
inverse = {valeur: cle for cle, valeur in original.items()}
print(inverse) # {1: 'a', 2: 'b', 3: 'c'}
# Créer un index de films par réalisateur
films_par_real = {
film["realisateur"]: film["titre"]
for film in films
}
print(films_par_real)
# {'Nolan': 'Interstellar', 'Tarantino': 'Pulp Fiction', ...}
Note : Si plusieurs films ont le même réalisateur, seul le dernier sera gardé. Pour grouper, il faut une approche différente.
Grouper avec defaultdict
from collections import defaultdict
# Grouper les films par réalisateur
films_groupes = defaultdict(list)
for film in films:
films_groupes[film["realisateur"]].append(film["titre"])
# Convertir en dictionnaire normal
films_groupes = dict(films_groupes)
print(films_groupes)
# {'Nolan': ['Inception', 'Interstellar'],
# 'Tarantino': ['Pulp Fiction'], ...}
Compréhensions d'ensembles
Syntaxe :
{expression for element in iterable}
Exemples :
# Ensemble des réalisateurs uniques
realisateurs = {film["realisateur"] for film in films}
print(realisateurs) # {'Nolan', 'Tarantino', 'Coppola', 'Bong'}
# Ensemble des années de sortie
annees = {film["annee"] for film in films}
print(sorted(annees)) # [1972, 1994, 2010, 2014, 2019]
# Chiffres uniques dans une chaîne
chiffres = {int(c) for c in "123456789123" if c.isdigit()}
print(chiffres) # {1, 2, 3, 4, 5, 6, 7, 8, 9}
Performance : compréhensions vs boucles
Les compréhensions de listes sont généralement plus rapides que les boucles équivalentes. Voyons pourquoi.
Test de performance
import time
# Tester avec un grand nombre d'éléments
n = 1000000
# Méthode 1 : Boucle classique
start = time.time()
resultat1 = []
for i in range(n):
resultat1.append(i ** 2)
temps1 = time.time() - start
# Méthode 2 : Compréhension de liste
start = time.time()
resultat2 = [i ** 2 for i in range(n)]
temps2 = time.time() - start
print(f"Boucle classique : {temps1:.4f} secondes")
print(f"Compréhension : {temps2:.4f} secondes")
print(f"Gain : {(temps1/temps2 - 1) * 100:.1f}%")
Résultat typique :
Boucle classique : 0.1234 secondes
Compréhension : 0.0891 secondes
Gain : 38.5%
Pourquoi c'est plus rapide ?
-
Optimisation interne : Python optimise les compréhensions au niveau du bytecode
-
Moins d'appels de méthode : pas besoin d'appeler
append()à chaque itération -
Allocation mémoire : Python peut pré-allouer la bonne taille de liste
Attention à la mémoire !
Les compréhensions créent toute la liste en mémoire d'un coup. Pour de très grandes données, utilisez plutôt des expressions génératrices.
Expressions génératrices : économiser la mémoire
Une expression génératrice ressemble à une compréhension de liste, mais utilise des parenthèses au lieu de crochets.
Syntaxe
(expression for element in iterable)
Différence clé
# Compréhension de liste : crée toute la liste en mémoire
liste = [i ** 2 for i in range(1000000)] # Occupe ~8 MB
# Expression génératrice : génère les valeurs à la demande
generateur = (i ** 2 for i in range(1000000)) # Occupe ~120 bytes
Utilisation
# On peut itérer dessus
for valeur in generateur:
print(valeur)
if valeur > 100:
break
# Ou convertir en liste si besoin
liste = list(generateur)
# Utile avec sum(), max(), etc.
nombres = range(1000000)
somme = sum(n ** 2 for n in nombres) # Pas besoin de créer la liste !
Quand utiliser quoi ?
-
Compréhension de liste : quand vous avez besoin de la liste complète, ou qu'elle est petite
-
Expression génératrice : pour les grandes données, ou quand vous n'itérez qu'une fois
Erreurs courantes et pièges à éviter
Erreur 1 : Ordre du if-else
# ❌ ERREUR : if-else après le for
nombres = [n if n > 5 for n in range(10)] # SyntaxError
# ✅ CORRECT : if-else avant le for
nombres = [n if n > 5 else 0 for n in range(10)]
Erreur 2 : Modifier la liste source
# ❌ ATTENTION : comportement inattendu
nombres = [1, 2, 3, 4, 5]
doubles = [nombres.append(n * 2) for n in nombres]
# append() retourne None, donc doubles = [None, None, ...]
# ✅ CORRECT : créer une nouvelle liste
doubles = [n * 2 for n in nombres]
Erreur 3 : Compréhensions trop complexes
# ❌ LISIBILITÉ : trop complexe
resultat = [
x * y + z
for x in range(10)
for y in range(10)
for z in range(10)
if x > 5
if y < 3
if z % 2 == 0
]
# ✅ MEILLEUR : boucles explicites pour la complexité
resultat = []
for x in range(10):
if x > 5:
for y in range(10):
if y < 3:
for z in range(10):
if z % 2 == 0:
resultat.append(x * y + z)
Règle d'or : Si votre compréhension dépasse une ligne ou devient difficile à lire, utilisez une boucle classique.
Cas d'usage pratiques
1. Nettoyer des données
# Données brutes avec espaces et majuscules
emails_bruts = [" ALICE@MAIL.COM ", "bob@MAIL.com", " charlie@mail.COM"]
# Nettoyer
emails_propres = [email.strip().lower() for email in emails_bruts]
print(emails_propres)
# ['alice@mail.com', 'bob@mail.com', 'charlie@mail.com']
2. Parser des fichiers
# Simuler le contenu d'un fichier CSV
lignes = [
"nom,age,ville",
"Alice,25,Paris",
"Bob,30,Lyon",
"Charlie,35,Marseille"
]
# Parser (skip header)
donnees = [ligne.split(',') for ligne in lignes[1:]]
print(donnees)
# [['Alice', '25', 'Paris'], ['Bob', '30', 'Lyon'], ...]
# Créer des dictionnaires
headers = lignes[0].split(',')
personnes = [
{headers[i]: valeur for i, valeur in enumerate(ligne.split(','))}
for ligne in lignes[1:]
]
print(personnes)
# [{'nom': 'Alice', 'age': '25', 'ville': 'Paris'}, ...]
3. Filtrer et transformer des URLs
urls = [
"https://site.com/page1",
"http://site.com/page2",
"https://autre.com/page3",
"ftp://serveur.com/fichier"
]
# Garder seulement les HTTPS de site.com
urls_securisees = [
url
for url in urls
if url.startswith("https://") and "site.com" in url
]
print(urls_securisees) # ['https://site.com/page1']
4. Valider des données
# Emails à valider
emails = ["alice@mail.com", "bob@", "charlie@mail.com", "@domain.com", "diana@mail"]
# Validation simple
emails_valides = [
email
for email in emails
if "@" in email and email.count("@") == 1 and "." in email.split("@")[1]
]
print(emails_valides) # ['alice@mail.com', 'charlie@mail.com']
Exercices pratiques
Essayez de résoudre ces exercices en utilisant des compréhensions de listes :
Exercice 1 : FizzBuzz
Créez une liste de 1 à 100 où :
-
Les multiples de 3 deviennent "Fizz"
-
Les multiples de 5 deviennent "Buzz"
-
Les multiples de 3 ET 5 deviennent "FizzBuzz"
-
Les autres restent des nombres
Exercice 2 : Mots en zigzag
À partir d'une phrase, créez une liste alternant minuscules et majuscules pour chaque mot.
Exercice 3 : Matrice transposée
Transposez une matrice (lignes ↔ colonnes) avec une compréhension.
Exercice 4 : Compter les voyelles
Créez une liste du nombre de voyelles dans chaque mot d'une phrase.
Solutions
Cliquez pour voir les solutions
# Solution 1 : FizzBuzz
fizzbuzz = [
"FizzBuzz" if n % 15 == 0 else
"Fizz" if n % 3 == 0 else
"Buzz" if n % 5 == 0 else
n
for n in range(1, 101)
]
# Solution 2 : Mots en zigzag
phrase = "Python est vraiment génial"
zigzag = [
mot.upper() if i % 2 == 0 else mot.lower()
for i, mot in enumerate(phrase.split())
]
# ['PYTHON', 'est', 'VRAIMENT', 'génial']
# Solution 3 : Matrice transposée
matrice = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposee = [[ligne[i] for ligne in matrice] for i in range(len(matrice[0]))]
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
# Solution 4 : Compter les voyelles
phrase = "Python est génial"
voyelles = "aeiouyAEIOUY"
compte = [
sum(1 for lettre in mot if lettre in voyelles)
for mot in phrase.split()
]
# [1, 1, 3] (Python: o, est: e, génial: e,i,a)
Conclusion
Les compréhensions de listes sont un outil essentiel dans l'arsenal de tout développeur Python. Elles permettent d'écrire du code :
-
Plus concis : une ligne au lieu de quatre
-
Plus lisible : l'intention est claire
-
Plus performant : optimisées par Python
-
Plus pythonique : idiomatique et élégant
Les points clés à retenir :
-
Syntaxe de base :
[expression for element in iterable] -
Avec filtre :
[expression for element in iterable if condition] -
Avec if-else :
[expr_if if cond else expr_else for element in iterable] -
Aussi pour les dictionnaires :
{cle: valeur for element in iterable} -
Et les ensembles :
{expression for element in iterable} -
Expressions génératrices :
(expression for element in iterable)pour économiser la mémoire
N'oubliez pas : si votre compréhension devient trop complexe, préférez une boucle classique pour la lisibilité. Le code doit rester compréhensible, même un mois après l'avoir écrit!

Laisser un commentaire