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 :
[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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
[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 :
# 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 :
# 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 :
# 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 :
# 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 :
[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 deelse - Expression conditionnelle :
[expr_if if cond else expr_else for item in seq]-if-elsedans l’expression, avantfor
# 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 :
# 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-elsedé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 :
# 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émentExpression conditionnelle (if-else dans l’expression) - Tous les éléments sont inclus mais transformés différemment :
# 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ésultat34.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 :
{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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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é :
# 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 :
# 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 :
# 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 :
# 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 :
{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.
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
- Vous avez besoin de valeurs uniques : supprime automatiquement les doublons
- 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
- Vous effectuerez des opérations ensemblistes : le résultat peut être utilisé avec union, intersection, etc. (comme nous l’avons vu au Chapitre 17)
# 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 :
- Créer une nouvelle collection à partir d’une collection existante :
# Bon usage d’une compréhension
prices = [10.99, 25.50, 8.75, 15.00]
discounted = [price * 0.9 for price in prices]- La transformation est simple :
# Clair et concis
names = ["alice", "bob", "charlie"]
uppercase_names = [name.upper() for name in names]- Filtrer selon des conditions simples :
# 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 :
- La logique est complexe ou implique plusieurs étapes :
# 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.
- Vous devez effectuer des actions au-delà de la création d’une collection :
# 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- Vous devez modifier une collection existante sur place :
# 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]- Vous devez utiliser break ou continue avec une logique complexe :
# 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}")
break34.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 :
# 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.
# 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 :
# 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!")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 :
[expression for item1 in iterable1 for item2 in iterable2]Cela équivaut à :
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 :
# 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 :
# 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 :
# 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 = 934.6.3) Aplatir des listes imbriquées
Plusieurs clauses for sont utiles pour aplatir des structures imbriquées :
# 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 à :
flat = []
for sublist in nested_numbers:
for num in sublist:
flat.append(num)Aplatir une liste de mots en caractères :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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 :
# 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.