Python & AI Tutorials Logo
Programmation Python

34. Compréhensions : une manière compacte de créer des listes, des dictionnaires et des ensembles

Les compréhensions sont l’une des fonctionnalités les plus élégantes de Python : elles vous permettent de créer et de transformer des collections en une seule ligne de code, lisible. Au lieu d’écrire plusieurs lignes avec des boucles(loop) et des opérations append, les compréhensions vous permettent d’exprimer la même logique de façon plus concise et souvent plus clairement.

Dans ce chapitre, nous allons explorer comment utiliser les compréhensions de liste(list comprehensions), les compréhensions de dictionnaire(dictionary comprehensions) et les compréhensions d’ensemble(set comprehensions) pour écrire du code plus « Pythonic ». Nous verrons comment intégrer une logique conditionnelle, quand choisir les compréhensions plutôt que les boucles traditionnelles, et comment gérer des scénarios plus complexes avec des itérations imbriquées.

34.1) Compréhensions de liste pour créer et transformer des listes

34.1.1) La syntaxe de base d’une compréhension de liste

Une compréhension de liste(list comprehension) fournit une manière compacte de créer une nouvelle liste en appliquant une expression à chaque élément d’une séquence existante. La syntaxe de base est :

python
[expression for item in iterable]

Cela crée une nouvelle liste où chaque élément est le résultat de l’évaluation de expression pour chaque item dans l’iterable (toute séquence sur laquelle vous pouvez boucler, comme une liste, un range, ou une chaîne de caractères).

Commençons par un exemple simple. Supposons que nous voulions créer une liste des carrés des nombres de 0 à 4 :

python
# Approche traditionnelle avec une boucle
squares = []
for number in range(5):
    squares.append(number ** 2)
print(squares)  # Output: [0, 1, 4, 9, 16]

Avec une compréhension de liste, nous pouvons exprimer cela plus concisément :

python
# Utiliser une compréhension de liste
squares = [number ** 2 for number in range(5)]
print(squares)  # Output: [0, 1, 4, 9, 16]

Les deux approches produisent le même résultat, mais la compréhension est plus compacte et, une fois que vous êtes familiarisé avec la syntaxe, souvent plus facile à lire. La compréhension montre clairement que nous créons une liste de valeurs élevées au carré.

34.1.2) Transformer des données existantes

Les compréhensions de liste excellent pour transformer des données d’une forme à une autre. Regardons quelques exemples pratiques.

Convertir des températures de Celsius en Fahrenheit :

python
# Données de température en Celsius
celsius_temps = [0, 10, 20, 30, 40]
 
# Conversion en Fahrenheit avec la formule : F = C * 9/5 + 32
fahrenheit_temps = [temp * 9/5 + 32 for temp in celsius_temps]
print(fahrenheit_temps)  # Output: [32.0, 50.0, 68.0, 86.0, 104.0]

Convertir des chaînes en majuscules :

python
# Codes produit avec une casse mixte
product_codes = ["abc123", "def456", "ghi789"]
 
# Normaliser en majuscules
uppercase_codes = [code.upper() for code in product_codes]
print(uppercase_codes)  # Output: ['ABC123', 'DEF456', 'GHI789']

34.1.3) Créer des listes à partir d’objets range

Les compréhensions de liste fonctionnent naturellement avec range(), que nous avons vu au Chapitre 12. C’est utile pour générer des séquences avec des motifs spécifiques :

python
# Générer des nombres pairs de 0 à 10
evens = [n * 2 for n in range(6)]  # n va de 0 à 5, donc n*2 donne 0, 2, 4, 6, 8, 10
print(evens)  # Output: [0, 2, 4, 6, 8, 10]
 
# Générer des multiples de 5
multiples_of_five = [n * 5 for n in range(1, 6)]
print(multiples_of_five)  # Output: [5, 10, 15, 20, 25]

34.1.4) Compréhensions vs construire des listes avec append

Il est important de comprendre que les compréhensions de liste créent la liste entière en une seule opération, alors que l’approche traditionnelle avec une boucle construit la liste progressivement. Les deux produisent le même résultat, mais les compréhensions sont généralement plus rapides pour créer de nouvelles listes et sont considérées comme plus « Pythonic ».

Voici une comparaison côte à côte :

python
# Approche traditionnelle avec une boucle
result = []
for i in range(5):
    result.append(i * 3)
print(result)  # Output: [0, 3, 6, 9, 12]
 
# Approche par compréhension de liste
result = [i * 3 for i in range(5)]
print(result)  # Output: [0, 3, 6, 9, 12]

Les deux approches sont valides, mais la compréhension est plus concise et exprime clairement l’intention : « créer une liste de valeurs où chaque valeur vaut i * 3 ».

34.2) Logique conditionnelle dans les compréhensions de liste

34.2.1) Filtrer avec des conditions if

L’une des fonctionnalités les plus puissantes des compréhensions de liste est la capacité à filtrer des éléments selon une condition. Vous pouvez ajouter une clause if à la fin de la compréhension pour n’inclure que les éléments qui répondent à certains critères :

python
[expression for item in iterable if condition]

La clause if agit comme un filtre(filter) : Python évalue la condition pour chaque élément, et seuls les éléments pour lesquels la condition vaut True seront inclus dans la liste résultante. Les éléments qui ne satisfont pas la condition sont entièrement ignorés.

Voyons cela en action avec un exemple simple :

python
# Obtenir uniquement les nombres pairs de 0 à 9
numbers = range(10)
evens = [n for n in numbers if n % 2 == 0]
print(evens)  # Output: [0, 2, 4, 6, 8]

Ici, n % 2 == 0 vérifie si un nombre est pair. Seuls les nombres qui passent ce test sont inclus dans la nouvelle liste.

Filtrer les notes d’étudiants :

python
# Notes de test des étudiants
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Obtenir uniquement les notes de passage (>= 70)
passing_scores = [score for score in scores if score >= 70]
print(passing_scores)  # Output: [78, 92, 88, 73, 95]

34.2.2) Transformer des éléments filtrés

Vous pouvez combiner filtrage et transformation en appliquant une expression aux éléments filtrés :

python
# Notes des étudiants
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Obtenir les notes de passage et les mettre à l’échelle sur 0-10
scaled_passing = [score / 10 for score in scores if score >= 70]
print(scaled_passing)  # Output: [7.8, 9.2, 8.8, 7.3, 9.5]
# Filtre d’abord (ne garde que >= 70), puis transforme (divise par 10)

Convertir et filtrer des chaînes :

python
# Noms de produits de qualité mixte
products = ["apple", "BANANA", "cherry", "DATE", "elderberry"]
 
# Obtenir les versions en majuscules des produits dont le nom dépasse 5 caractères
long_products_upper = [product.upper() for product in products if len(product) > 5]
print(long_products_upper)  # Output: ['BANANA', 'CHERRY', 'ELDERBERRY']

34.2.3) Utiliser des expressions conditionnelles (if-else) dans les compréhensions

Parfois, vous voulez transformer les éléments différemment selon une condition, plutôt que de les filtrer. Pour cela, vous utilisez une expression conditionnelle(conditional expression) (que nous avons vue au Chapitre 10) dans la partie expression de la compréhension :

python
[expression_if_true if condition else expression_if_false for item in iterable]

C’est différent du filtrage. Ici, chaque élément est inclus dans le résultat — le if-else détermine quelle expression appliquer à chaque élément. L’expression conditionnelle (du Chapitre 10) apparaît dans la partie expression, avant la clause for.

Notez la différence de syntaxe :

  • Filtrage : [expr for item in seq if condition] - if à la fin, pas de else
  • Expression conditionnelle : [expr_if if cond else expr_else for item in seq] - if-else dans l’expression, avant for
python
# Classer des nombres comme pairs ou impairs
numbers = range(6)
classifications = ["even" if n % 2 == 0 else "odd" for n in numbers]
print(classifications)  # Output: ['even', 'odd', 'even', 'odd', 'even', 'odd']

Appliquer différentes transformations selon des conditions :

python
# Notes des étudiants
scores = [45, 78, 92, 65, 88, 55, 73, 95]
 
# Ajouter des points bonus aux notes insuffisantes, garder les notes de passage telles quelles
adjusted_scores = [score + 10 if score < 70 else score for score in scores]
print(adjusted_scores)  # Output: [55, 78, 92, 75, 88, 65, 73, 95]

Dans les deux exemples, notez que :

  • Chaque élément de la liste d’origine apparaît dans le résultat
  • Le if-else détermine la valeur que devient chaque élément
  • Aucun élément n’est filtré

34.2.4) Comprendre la différence : filtrage vs expression conditionnelle

Il est crucial de comprendre la différence entre ces deux motifs :

Filtrage (if à la fin) - Certains éléments sont exclus :

python
# Inclure uniquement les nombres positifs
numbers = [-2, 5, -1, 8, 0, 3]
positives = [n for n in numbers if n > 0]
print(positives)  # Output: [5, 8, 3]
print(len(positives))  # Output: 3 (seulement 3 éléments)
# Processus : vérifier la condition → si True, inclure l’élément → si False, ignorer l’élément

Expression conditionnelle (if-else dans l’expression) - Tous les éléments sont inclus mais transformés différemment :

python
# Convertir les nombres négatifs en zéro, garder les nombres positifs
numbers = [-2, 5, -1, 8, 0, 3]
non_negatives = [n if n > 0 else 0 for n in numbers]
print(non_negatives)  # Output: [0, 5, 0, 8, 0, 3]
print(len(non_negatives))  # Output: 6 (les 6 éléments)
# Processus : vérifier la condition → si True, utiliser la première expr → si False, utiliser la seconde expr → toujours inclure le résultat

À la FIN
sans else

Dans l’EXPRESSION
avec else

Compréhension de liste
avec condition

Où se trouve
le if ?

Filtrage

Expression conditionnelle

[x for x in items if condition]

[x if condition else y for x in items]

Certains éléments exclus
Le résultat peut être plus court

Tous les éléments inclus
Même longueur que l’original

34.3) Compréhensions de dictionnaire

34.3.1) Syntaxe de base d’une compréhension de dictionnaire

Tout comme les compréhensions de liste créent des listes, les compréhensions de dictionnaire(dictionary comprehensions) créent des dictionnaires. La syntaxe est similaire, mais vous spécifiez à la fois une clé et une valeur :

python
{key_expression: value_expression for item in iterable}

Cela crée un nouveau dictionnaire où chaque paire clé-valeur est générée à partir de l’itérable.

Commençons par un exemple simple qui crée un dictionnaire associant des nombres à leurs carrés :

python
# Créer un dictionnaire de nombres et de leurs carrés
squares_dict = {n: n ** 2 for n in range(5)}
print(squares_dict)  # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Créer un dictionnaire à partir de deux listes :

python
# Noms des étudiants et leurs scores
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
 
# Créer un dictionnaire associant les noms aux scores
student_scores = {names[i]: scores[i] for i in range(len(names))}
print(student_scores)  # Output: {'Alice': 85, 'Bob': 92, 'Charlie': 78}

Une manière plus élégante de combiner deux séquences consiste à utiliser zip(), que nous verrons au Chapitre 37. Pour l’instant, l’approche basée sur les indices fonctionne bien.

34.3.2) Transformer des dictionnaires existants

Les compréhensions de dictionnaire sont excellentes pour transformer des dictionnaires existants. Vous pouvez modifier les clés, les valeurs, ou les deux.

Quand vous itérez sur un dictionnaire dans une compréhension, utilisez .items() pour accéder à la fois aux clés et aux valeurs. La méthode .items() renvoie des paires clé-valeur que vous pouvez décompacter dans la clause for :

python
# Prix originaux en dollars
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.00}
 
# Convertir en cents (multiplier par 100)
prices_in_cents = {fruit: price * 100 for fruit, price in prices.items()}
print(prices_in_cents)  # Output: {'apple': 150.0, 'banana': 75.0, 'cherry': 200.0}

Transformer les clés :

python
# Codes produit en minuscules
codes = {"abc": 100, "def": 200, "ghi": 300}
 
# Convertir les clés en majuscules
uppercase_codes = {code.upper(): quantity for code, quantity in codes.items()}
print(uppercase_codes)  # Output: {'ABC': 100, 'DEF': 200, 'GHI': 300}

Transformer à la fois les clés et les valeurs :

python
# Noms des étudiants et scores
scores = {"alice": 85, "bob": 92, "charlie": 78}
 
# Mettre les noms en capitales et mettre les scores à l’échelle sur 0-10
formatted_scores = {name.capitalize(): score / 10 for name, score in scores.items()}
print(formatted_scores)  # Output: {'Alice': 8.5, 'Bob': 9.2, 'Charlie': 7.8}

34.3.3) Filtrer des éléments de dictionnaire

Comme les compréhensions de liste, les compréhensions de dictionnaire peuvent inclure des conditions pour filtrer des éléments :

python
# Scores des étudiants
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55, "Eve": 78}
 
# Obtenir uniquement les scores de passage (>= 70)
passing_scores = {name: score for name, score in scores.items() if score >= 70}
print(passing_scores)  # Output: {'Alice': 85, 'Charlie': 92, 'Eve': 78}

Filtrer selon des caractéristiques de clé :

python
# Stock de produits
inventory = {"apple": 50, "banana": 30, "apricot": 20, "cherry": 40}
 
# Obtenir uniquement les produits commençant par 'a'
a_products = {product: quantity for product, quantity in inventory.items() 
              if product.startswith('a')}
print(a_products)  # Output: {'apple': 50, 'apricot': 20}

34.3.4) Créer des dictionnaires à partir de séquences

Les compréhensions de dictionnaire sont utiles pour créer des dictionnaires de recherche à partir de séquences :

python
# Liste de mots
words = ["python", "java", "ruby", "javascript"]
 
# Créer un dictionnaire associant chaque mot à sa longueur
word_lengths = {word: len(word) for word in words}
print(word_lengths)  # Output: {'python': 6, 'java': 4, 'ruby': 4, 'javascript': 10}

34.3.5) Utiliser des expressions conditionnelles dans les compréhensions de dictionnaire

Vous pouvez utiliser des expressions conditionnelles pour calculer des valeurs différemment selon des conditions :

python
# Scores des étudiants
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55}
 
# Ajouter un statut "Pass" ou "Fail"
scores_with_status = {name: "Pass" if score >= 70 else "Fail" 
                      for name, score in scores.items()}
print(scores_with_status)  # Output: {'Alice': 'Pass', 'Bob': 'Fail', 'Charlie': 'Pass', 'David': 'Fail'}

Appliquer différentes transformations :

python
# Prix des produits
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.50}
 
# Appliquer une réduction aux articles chers (> $2.00)
discounted_prices = {product: price * 0.9 if price > 2.00 else price 
                     for product, price in prices.items()}
print(discounted_prices)  # Output: {'apple': 1.5, 'banana': 0.75, 'cherry': 2.25}

34.4) Compréhensions d’ensemble

34.4.1) Syntaxe de base d’une compréhension d’ensemble

Les compréhensions d’ensemble(set comprehensions) créent des ensembles en utilisant une syntaxe similaire aux compréhensions de liste, mais avec des accolades :

python
{expression for item in iterable}

Le résultat est un ensemble, ce qui signifie que les valeurs en double sont automatiquement supprimées et que l’ordre n’est pas garanti.

python
# Créer un ensemble de carrés
squares_set = {n ** 2 for n in range(6)}
print(squares_set)  # Output: {0, 1, 4, 9, 16, 25}

La principale différence avec les compréhensions de liste est que les ensembles éliminent automatiquement les doublons :

python
# Compréhension de liste - conserve les doublons
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
squared_list = [n ** 2 for n in numbers]
print(squared_list)  # Output: [1, 4, 4, 9, 9, 9, 16, 16, 16, 16]
 
# Compréhension d’ensemble - supprime les doublons
squared_set = {n ** 2 for n in numbers}
print(squared_set)  # Output: {16, 1, 4, 9} (order may vary)

Notez que l’ordre d’affichage de l’ensemble peut différer de ce que vous voyez ici. Les ensembles sont des collections non ordonnées, donc Python peut afficher les éléments dans n’importe quel ordre.

34.4.2) Extraire des valeurs uniques

Les compréhensions d’ensemble sont parfaites lorsque vous devez extraire des valeurs uniques d’une collection :

python
# Réponses d’étudiants (avec doublons)
responses = ["yes", "no", "yes", "maybe", "no", "yes", "maybe"]
 
# Obtenir les réponses uniques
unique_responses = {response for response in responses}
print(unique_responses)  # Output: {'maybe', 'yes', 'no'}

Extraire des caractères uniques d’une chaîne :

python
# Texte avec des caractères répétés
text = "mississippi"
 
# Obtenir les caractères uniques
unique_chars = {char for char in text}
print(unique_chars)  # Output: {'m', 'i', 's', 'p'}

34.4.3) Transformer et filtrer avec des compréhensions d’ensemble

Comme les autres compréhensions, les compréhensions d’ensemble peuvent inclure des transformations et des conditions :

python
# Noms des étudiants
names = ["Alice", "bob", "CHARLIE", "david", "EVE"]
 
# Obtenir les premières lettres uniques en majuscules
first_letters = {name[0].upper() for name in names}
print(first_letters)  # Output: {'A', 'B', 'C', 'D', 'E'}

Filtrer avec des conditions :

python
# Nombres avec doublons
numbers = [1, -2, 3, -4, 5, -2, 3, 6, -4]
 
# Obtenir les nombres positifs uniques
positive_numbers = {n for n in numbers if n > 0}
print(positive_numbers)  # Output: {1, 3, 5, 6}

34.4.4) Quand les compréhensions d’ensemble sont les plus utiles

Les compréhensions d’ensemble sont particulièrement utiles lorsque :

  1. Vous avez besoin de valeurs uniques : supprime automatiquement les doublons
  2. L’ordre n’a pas d’importance : les ensembles ne sont pas ordonnés, donc utilisez-les quand la séquence n’est pas importante
  3. Vous effectuerez des opérations ensemblistes : le résultat peut être utilisé avec union, intersection, etc. (comme nous l’avons vu au Chapitre 17)
python
# Inscriptions d’étudiants à deux cours
course_a = ["Alice", "Bob", "Charlie", "David"]
course_b = ["Charlie", "David", "Eve", "Frank"]
 
# Obtenir les étudiants uniques sur les deux cours avec une compréhension d’ensemble
all_students = {student for course in [course_a, course_b] for student in course}
print(all_students)  # Output: {'Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank'}

34.5) Choisir entre compréhensions et boucles

34.5.1) Quand les compréhensions sont meilleures

Les compréhensions sont généralement préférées lorsque vous créez une nouvelle collection en transformant ou en filtrant une collection existante. Elles sont plus concises, souvent plus lisibles, et généralement plus rapides que des boucles équivalentes.

Les compréhensions excellent quand :

  1. Créer une nouvelle collection à partir d’une collection existante :
python
# Bon usage d’une compréhension
prices = [10.99, 25.50, 8.75, 15.00]
discounted = [price * 0.9 for price in prices]
  1. La transformation est simple :
python
# Clair et concis
names = ["alice", "bob", "charlie"]
uppercase_names = [name.upper() for name in names]
  1. Filtrer selon des conditions simples :
python
# Facile à comprendre
scores = [85, 92, 78, 65, 88, 55, 73, 95]
passing = [score for score in scores if score >= 70]

34.5.2) Quand les boucles traditionnelles sont meilleures

Cependant, il existe des situations où les boucles traditionnelles sont plus appropriées et plus lisibles :

Utilisez des boucles quand :

  1. La logique est complexe ou implique plusieurs étapes :
python
# Trop complexe pour une compréhension
results = []
for score in scores:
    if score >= 90:
        grade = "A"
    elif score >= 80:
        grade = "B"
    elif score >= 70:
        grade = "C"
    else:
        grade = "F"
    results.append({"score": score, "grade": grade})

Même si vous pourriez écrire cela comme une compréhension, ce serait beaucoup plus difficile à lire.

  1. Vous devez effectuer des actions au-delà de la création d’une collection :
python
# La boucle est plus claire lorsqu’on effectue des E/S ou des effets de bord
for filename in files:
    with open(filename) as f:
        content = f.read()
        print(f"Processing {filename}")
        # ... more processing
  1. Vous devez modifier une collection existante sur place :
python
# Modifier une liste sur place - impossible avec une compréhension
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
    numbers[i] *= 2
print(numbers)  # Output: [2, 4, 6, 8, 10]
  1. Vous devez utiliser break ou continue avec une logique complexe :
python
# Trouver la première occurrence avec un traitement supplémentaire
found = None
for item in items:
    if item.startswith("target"):
        found = item
        print(f"Found: {found}")
        break

34.5.3) Considérations de lisibilité

Le facteur le plus important est la lisibilité. Si une compréhension devient trop longue ou trop complexe, remplacez-la par une boucle traditionnelle :

python
# Difficile à lire - trop de choses sur une ligne
result = [item.upper().strip() for item in items if len(item) > 5 and item.startswith('a')]
 
# Mieux - utiliser une boucle lorsque la logique est complexe
result = []
for item in items:
    if len(item) > 5 and item.startswith('a'):
        cleaned = item.strip().upper()
        result.append(cleaned)

Une bonne règle empirique : si votre compréhension ne tient pas confortablement sur une ligne (ou au maximum deux lignes avec une mise en forme claire), envisagez d’utiliser une boucle à la place.

34.5.4) Considérations de performance

Les compréhensions sont généralement plus rapides que des boucles équivalentes, car elles sont optimisées au niveau de l’interpréteur. Cependant, cette différence de performance est en général négligeable pour des collections petites à moyennes.

python
# Les deux produisent le même résultat
# La compréhension est légèrement plus rapide
squares_comp = [n ** 2 for n in range(1000)]
 
# La boucle est légèrement plus lente mais plus flexible
squares_loop = []
for n in range(1000):
    squares_loop.append(n ** 2)

Pour la plupart des cas pratiques, choisissez en fonction de la lisibilité plutôt que de la performance. N’optimisez pour la vitesse que si un profilage montre qu’une opération particulière est un goulot d’étranglement.

34.5.5) Combiner les approches

Parfois, la meilleure solution combine les deux approches :

python
# Utiliser une compréhension pour une transformation simple
student_data = [
    {"name": "Alice", "score": 85},
    {"name": "Bob", "score": 92},
    {"name": "Charlie", "score": 78}
]
 
# Extraire les scores avec une compréhension
scores = [student["score"] for student in student_data]
 
# Utiliser une boucle pour un traitement complexe
for student in student_data:
    score = student["score"]
    if score >= 90:
        print(f"{student['name']}: Excellent!")
    elif score >= 80:
        print(f"{student['name']}: Good job!")
    else:
        print(f"{student['name']}: Keep working!")

Oui

Non

Oui

Non

Oui

Non

Oui

Non

Besoin de créer une collection ?

Transformation simple
ou filtrage ?

Utiliser une compréhension

Logique complexe ou
plusieurs étapes ?

Utiliser une boucle

Besoin d’effets de bord
ou d’E/S ?

Tient sur 1-2 lignes
et lisible ?

34.6) Boucles imbriquées et multiples clauses for

34.6.1) Comprendre les multiples clauses for

Les compréhensions peuvent inclure plusieurs clauses for, ce qui équivaut à des boucles imbriquées. La syntaxe est :

python
[expression for item1 in iterable1 for item2 in iterable2]

Cela équivaut à :

python
result = []
for item1 in iterable1:
    for item2 in iterable2:
        result.append(expression)

Le point clé est que les clauses for se lisent de gauche à droite, tout comme les boucles imbriquées s’écrivent de haut en bas.

Commençons par un exemple simple qui crée toutes les combinaisons de deux listes :

python
# Deux listes de valeurs
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
 
# Créer toutes les combinaisons
combinations = [(color, size) for color in colors for size in sizes]
print(combinations)
# Output: [('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]

Cela crée chaque association possible entre une couleur et une taille.

34.6.2) Créer des paires de coordonnées

Un cas d’usage courant consiste à générer des paires de coordonnées :

python
# Créer une grille 3x3 de coordonnées
coordinates = [(x, y) for x in range(3) for y in range(3)]
print(coordinates)
# Output: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

Créer une table de multiplication :

python
# Générer des triplets de multiplication
products = [(x, y, x * y) for x in range(1, 4) for y in range(1, 4)]
for x, y, product in products:
    print(f"{x} × {y} = {product}")
# Output:
# 1 × 1 = 1
# 1 × 2 = 2
# 1 × 3 = 3
# 2 × 1 = 2
# 2 × 2 = 4
# 2 × 3 = 6
# 3 × 1 = 3
# 3 × 2 = 6
# 3 × 3 = 9

34.6.3) Aplatir des listes imbriquées

Plusieurs clauses for sont utiles pour aplatir des structures imbriquées :

python
# Liste imbriquée de nombres
nested_numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 
# Aplatir en une seule liste
flat = [num for sublist in nested_numbers for num in sublist]
print(flat)  # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]

Cela équivaut à :

python
flat = []
for sublist in nested_numbers:
    for num in sublist:
        flat.append(num)

Aplatir une liste de mots en caractères :

python
# Liste de mots
words = ["cat", "dog", "bird"]
 
# Obtenir tous les caractères de tous les mots
all_chars = [char for word in words for char in word]
print(all_chars)  # Output: ['c', 'a', 't', 'd', 'o', 'g', 'b', 'i', 'r', 'd']

34.6.4) Ajouter des conditions aux compréhensions imbriquées

Vous pouvez ajouter des conditions pour filtrer les résultats :

python
# Créer des paires dont la somme est paire
pairs = [(x, y) for x in range(5) for y in range(5) if (x + y) % 2 == 0]
print(pairs)
# Output: [(0, 0), (0, 2), (0, 4), (1, 1), (1, 3), (2, 0), (2, 2), (2, 4), (3, 1), (3, 3), (4, 0), (4, 2), (4, 4)]

Trouver des éléments communs entre des listes :

python
# Deux listes de nombres
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
 
# Trouver les valeurs communes (éléments communs)
common = [x for x in list1 for y in list2 if x == y]
print(common)  # Output: [4, 5]

Remarque : pour trouver des éléments communs, utiliser l’intersection d’ensembles est plus efficace : set(list1) & set(list2), comme nous l’avons vu au Chapitre 17.

34.6.5) Compréhensions de dictionnaire imbriquées

Vous pouvez également utiliser plusieurs clauses for dans des compréhensions de dictionnaire :

python
# Créer un dictionnaire des sommes de coordonnées
coord_sums = {(x, y): x + y for x in range(3) for y in range(3)}
print(coord_sums)
# Output: {(0, 0): 0, (0, 1): 1, (0, 2): 2, (1, 0): 1, (1, 1): 2, (1, 2): 3, (2, 0): 2, (2, 1): 3, (2, 2): 4}

34.6.6) Quand éviter les compréhensions imbriquées

Même si les compréhensions imbriquées sont puissantes, elles peuvent vite devenir difficiles à lire. Tenez compte de ces recommandations :

Acceptable - relativement simple :

python
# Deux niveaux d’imbrication, expression simple
matrix = [[i * j for j in range(3)] for i in range(3)]
print(matrix)  # Output: [[0, 0, 0], [0, 1, 2], [0, 2, 4]]

Ça devient complexe - envisagez une boucle :

python
# Trois niveaux d’imbrication - difficile à lire
result = [[[i + j + k for k in range(2)] for j in range(2)] for i in range(2)]
# Mieux avec des boucles imbriquées pour plus de clarté

Règle empirique : si vous avez plus de deux clauses for, ou si l’expression est complexe, utilisez plutôt des boucles imbriquées traditionnelles :

python
# Plus clair avec des boucles explicites
result = []
for i in range(2):
    middle = []
    for j in range(2):
        inner = []
        for k in range(2):
            inner.append(i + j + k)
        middle.append(inner)
    result.append(middle)

Les compréhensions avec plusieurs clauses for sont des outils puissants, mais souvenez-vous : la clarté est plus importante que la brièveté. Si une compréhension imbriquée devient difficile à comprendre, il vaut mieux utiliser des boucles explicites.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai