34. Comprehensions: un modo compatto per creare liste, dizionari e set
Le comprehension sono una delle funzionalità più eleganti di Python e ti permettono di creare e trasformare collezioni in una singola riga di codice leggibile. Invece di scrivere più righe con cicli(loop) e operazioni di append, le comprehension ti consentono di esprimere la stessa logica in modo più conciso e spesso più chiaro.
In questo capitolo esploreremo come usare le list comprehension, le dictionary comprehension e le set comprehension per scrivere codice più “Pythonic”. Vedremo come incorporare logica condizionale, quando scegliere le comprehension rispetto ai cicli tradizionali e come gestire scenari più complessi con iterazioni annidate.
34.1) List Comprehensions per creare e trasformare liste
34.1.1) La sintassi di base della list comprehension
Una list comprehension fornisce un modo compatto per creare una nuova lista applicando un’espressione a ogni elemento di una sequenza esistente. La sintassi di base è:
[expression for item in iterable]Questo crea una nuova lista in cui ogni elemento è il risultato della valutazione di expression per ogni item nell’iterable (qualsiasi sequenza su cui puoi iterare, come una lista, un range o una stringa).
Iniziamo con un esempio semplice. Supponiamo di voler creare una lista di quadrati per i numeri da 0 a 4:
# Approccio tradizionale con un ciclo
squares = []
for number in range(5):
squares.append(number ** 2)
print(squares) # Output: [0, 1, 4, 9, 16]Con una list comprehension, possiamo esprimere la stessa cosa in modo più conciso:
# Usando una list comprehension
squares = [number ** 2 for number in range(5)]
print(squares) # Output: [0, 1, 4, 9, 16]Entrambi gli approcci producono lo stesso risultato, ma la comprehension è più compatta e, una volta che hai familiarità con la sintassi, spesso più facile da leggere. La comprehension mostra chiaramente che stiamo creando una lista di valori al quadrato.
34.1.2) Trasformare dati esistenti
Le list comprehension eccellono nel trasformare i dati da una forma a un’altra. Vediamo alcuni esempi pratici.
Convertire temperature da Celsius a Fahrenheit:
# Dati di temperatura in Celsius
celsius_temps = [0, 10, 20, 30, 40]
# Converti in Fahrenheit usando la formula: 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]Convertire stringhe in maiuscolo:
# Codici prodotto con maiuscole/minuscole miste
product_codes = ["abc123", "def456", "ghi789"]
# Standardizza in maiuscolo
uppercase_codes = [code.upper() for code in product_codes]
print(uppercase_codes) # Output: ['ABC123', 'DEF456', 'GHI789']34.1.3) Creare liste a partire da oggetti range
Le list comprehension funzionano naturalmente con range(), che abbiamo visto nel Capitolo 12. Questo è utile per generare sequenze con schemi specifici:
# Genera numeri pari da 0 a 10
evens = [n * 2 for n in range(6)] # n va da 0 a 5, quindi n*2 dà 0, 2, 4, 6, 8, 10
print(evens) # Output: [0, 2, 4, 6, 8, 10]
# Genera multipli di 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) Comprehension vs costruire liste con append
È importante capire che le list comprehension creano l’intera lista in un’unica operazione, mentre l’approccio tradizionale con un ciclo costruisce la lista in modo incrementale. Entrambi producono lo stesso risultato, ma le comprehension sono in genere più veloci per creare nuove liste e sono considerate più “Pythonic”.
Ecco un confronto affiancato:
# Approccio tradizionale con un ciclo
result = []
for i in range(5):
result.append(i * 3)
print(result) # Output: [0, 3, 6, 9, 12]
# Approccio con list comprehension
result = [i * 3 for i in range(5)]
print(result) # Output: [0, 3, 6, 9, 12]Entrambi gli approcci sono validi, ma la comprehension è più concisa ed esprime chiaramente l’intento: “crea una lista di valori in cui ogni valore è i * 3”.
34.2) Logica condizionale dentro le list comprehension
34.2.1) Filtrare con condizioni if
Una delle funzionalità più potenti delle list comprehension è la possibilità di filtrare gli elementi in base a una condizione. Puoi aggiungere una clausola if alla fine della comprehension per includere solo gli elementi che soddisfano determinati criteri:
[expression for item in iterable if condition]La clausola if agisce come un filtro: Python valuta la condizione per ogni elemento e solo gli elementi per cui la condizione è True verranno inclusi nella lista risultante. Gli elementi che non soddisfano la condizione vengono saltati completamente.
Vediamolo in azione con un esempio semplice:
# Ottieni solo numeri pari da 0 a 9
numbers = range(10)
evens = [n for n in numbers if n % 2 == 0]
print(evens) # Output: [0, 2, 4, 6, 8]Qui, n % 2 == 0 verifica se un numero è pari. Solo i numeri che superano questo test vengono inclusi nella nuova lista.
Filtrare i punteggi degli studenti:
# Punteggi dei test degli studenti
scores = [45, 78, 92, 65, 88, 55, 73, 95]
# Ottieni solo i punteggi sufficienti (>= 70)
passing_scores = [score for score in scores if score >= 70]
print(passing_scores) # Output: [78, 92, 88, 73, 95]34.2.2) Trasformare gli elementi filtrati
Puoi combinare il filtraggio con la trasformazione applicando un’espressione agli elementi filtrati:
# Punteggi degli studenti
scores = [45, 78, 92, 65, 88, 55, 73, 95]
# Ottieni i punteggi sufficienti e riscalali nell'intervallo 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]
# Prima filtra (mantiene solo >= 70), poi trasforma (divide per 10)Convertire e filtrare stringhe:
# Nomi di prodotti con qualità mista
products = ["apple", "BANANA", "cherry", "DATE", "elderberry"]
# Ottieni le versioni in maiuscolo dei prodotti con nomi più lunghi di 5 caratteri
long_products_upper = [product.upper() for product in products if len(product) > 5]
print(long_products_upper) # Output: ['BANANA', 'CHERRY', 'ELDERBERRY']34.2.3) Usare espressioni condizionali (if-else) nelle comprehension
A volte vuoi trasformare gli elementi in modo diverso in base a una condizione, invece di filtrarli. Per farlo, usi un’espressione condizionale (che abbiamo visto nel Capitolo 10) nella parte dell’espressione della comprehension:
[expression_if_true if condition else expression_if_false for item in iterable]Questo è diverso dal filtraggio. Qui, ogni elemento è incluso nel risultato: l’if-else determina quale espressione applicare a ciascun elemento. L’espressione condizionale (dal Capitolo 10) appare nella parte dell’espressione, prima della clausola for.
Nota la differenza di sintassi:
- Filtraggio:
[expr for item in seq if condition]-ifalla fine, nessunelse - Espressione condizionale:
[expr_if if cond else expr_else for item in seq]-if-elsenell’espressione, prima difor
# Classifica i numeri come pari o dispari
numbers = range(6)
classifications = ["even" if n % 2 == 0 else "odd" for n in numbers]
print(classifications) # Output: ['even', 'odd', 'even', 'odd', 'even', 'odd']Applicare trasformazioni diverse in base alle condizioni:
# Punteggi degli studenti
scores = [45, 78, 92, 65, 88, 55, 73, 95]
# Aggiungi punti bonus ai punteggi insufficienti, mantieni invariati i punteggi sufficienti
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]In entrambi gli esempi, nota che:
- Ogni elemento della lista originale appare nel risultato
- L’
if-elsedetermina in che valore diventa ciascun elemento - Nessun elemento viene filtrato
34.2.4) Comprendere la differenza: filtraggio vs espressione condizionale
È fondamentale comprendere la differenza tra questi due schemi:
Filtraggio (if alla fine) - Alcuni elementi vengono esclusi:
# Includi solo numeri positivi
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 (solo 3 elementi)
# Processo: Verifica condizione → Se True, includi l'elemento → Se False, salta l'elementoEspressione condizionale (if-else nell’espressione) - Tutti gli elementi vengono inclusi ma trasformati in modo diverso:
# Converti i numeri negativi in zero, mantieni i numeri positivi
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 (tutti e 6 gli elementi)
# Processo: Verifica condizione → Se True, usa la prima expr → Se False, usa la seconda expr → Includi sempre il risultato34.3) Dictionary Comprehensions
34.3.1) Sintassi di base della dictionary comprehension
Così come le list comprehension creano liste, le dictionary comprehension creano dizionari. La sintassi è simile, ma specifichi sia una chiave sia un valore:
{key_expression: value_expression for item in iterable}Questo crea un nuovo dizionario in cui ogni coppia chiave-valore viene generata dall’iterabile.
Iniziamo con un esempio semplice che crea un dizionario che mappa i numeri ai loro quadrati:
# Crea un dizionario di numeri e dei loro quadrati
squares_dict = {n: n ** 2 for n in range(5)}
print(squares_dict) # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}Creare un dizionario da due liste:
# Nomi degli studenti e i loro punteggi
names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
# Crea un dizionario che mappa i nomi ai punteggi
student_scores = {names[i]: scores[i] for i in range(len(names))}
print(student_scores) # Output: {'Alice': 85, 'Bob': 92, 'Charlie': 78}Un modo più elegante per combinare due sequenze è usare zip(), che vedremo nel Capitolo 37. Per ora, l’approccio basato sugli indici funziona bene.
34.3.2) Trasformare dizionari esistenti
Le dictionary comprehension sono eccellenti per trasformare dizionari esistenti. Puoi modificare chiavi, valori o entrambi.
Quando iteri su un dizionario in una comprehension, usa .items() per accedere sia alle chiavi sia ai valori. Il metodo .items() restituisce coppie chiave-valore che puoi spacchettare nella clausola for:
# Prezzi originali in dollari
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.00}
# Converti in centesimi (moltiplica per 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}Trasformare le chiavi:
# Codici prodotto in minuscolo
codes = {"abc": 100, "def": 200, "ghi": 300}
# Converti le chiavi in maiuscolo
uppercase_codes = {code.upper(): quantity for code, quantity in codes.items()}
print(uppercase_codes) # Output: {'ABC': 100, 'DEF': 200, 'GHI': 300}Trasformare sia chiavi sia valori:
# Nomi degli studenti e punteggi
scores = {"alice": 85, "bob": 92, "charlie": 78}
# Metti in maiuscolo l'iniziale dei nomi e scala i punteggi nell'intervallo 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) Filtrare gli elementi del dizionario
Come le list comprehension, le dictionary comprehension possono includere condizioni per filtrare gli elementi:
# Punteggi degli studenti
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55, "Eve": 78}
# Ottieni solo i punteggi sufficienti (>= 70)
passing_scores = {name: score for name, score in scores.items() if score >= 70}
print(passing_scores) # Output: {'Alice': 85, 'Charlie': 92, 'Eve': 78}Filtrare in base alle caratteristiche della chiave:
# Inventario dei prodotti
inventory = {"apple": 50, "banana": 30, "apricot": 20, "cherry": 40}
# Ottieni solo i prodotti che iniziano con '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) Creare dizionari da sequenze
Le dictionary comprehension sono utili per creare dizionari di lookup a partire da sequenze:
# Lista di parole
words = ["python", "java", "ruby", "javascript"]
# Crea un dizionario che mappa ogni parola alla sua lunghezza
word_lengths = {word: len(word) for word in words}
print(word_lengths) # Output: {'python': 6, 'java': 4, 'ruby': 4, 'javascript': 10}34.3.5) Usare espressioni condizionali nelle dictionary comprehension
Puoi usare espressioni condizionali per calcolare i valori in modo diverso in base alle condizioni:
# Punteggi degli studenti
scores = {"Alice": 85, "Bob": 65, "Charlie": 92, "David": 55}
# Aggiungi lo stato "Pass" o "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'}Applicare trasformazioni diverse:
# Prezzi dei prodotti
prices = {"apple": 1.50, "banana": 0.75, "cherry": 2.50}
# Applica lo sconto agli articoli costosi (> $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) Set Comprehensions
34.4.1) Sintassi di base della set comprehension
Le set comprehension creano set usando una sintassi simile alle list comprehension, ma con parentesi graffe:
{expression for item in iterable}Il risultato è un set, il che significa che i valori duplicati vengono rimossi automaticamente e l’ordine non è garantito.
# Crea un set di quadrati
squares_set = {n ** 2 for n in range(6)}
print(squares_set) # Output: {0, 1, 4, 9, 16, 25}La differenza fondamentale rispetto alle list comprehension è che i set eliminano automaticamente i duplicati:
# List comprehension - mantiene i duplicati
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]
# Set comprehension - rimuove i duplicati
squared_set = {n ** 2 for n in numbers}
print(squared_set) # Output: {16, 1, 4, 9} (order may vary)Nota che l’ordine dell’output di un set può differire da quello che vedi qui. I set sono collezioni non ordinate, quindi Python può mostrare gli elementi in qualsiasi ordine.
34.4.2) Estrarre valori univoci
Le set comprehension sono perfette quando devi estrarre valori univoci da una collezione:
# Risposte degli studenti (con duplicati)
responses = ["yes", "no", "yes", "maybe", "no", "yes", "maybe"]
# Ottieni risposte univoche
unique_responses = {response for response in responses}
print(unique_responses) # Output: {'maybe', 'yes', 'no'}Estrarre caratteri univoci da stringhe:
# Testo con caratteri ripetuti
text = "mississippi"
# Ottieni caratteri univoci
unique_chars = {char for char in text}
print(unique_chars) # Output: {'m', 'i', 's', 'p'}34.4.3) Trasformare e filtrare con le set comprehension
Come le altre comprehension, anche le set comprehension possono includere trasformazioni e condizioni:
# Nomi degli studenti
names = ["Alice", "bob", "CHARLIE", "david", "EVE"]
# Ottieni prime lettere univoche in maiuscolo
first_letters = {name[0].upper() for name in names}
print(first_letters) # Output: {'A', 'B', 'C', 'D', 'E'}Filtrare con condizioni:
# Numeri con duplicati
numbers = [1, -2, 3, -4, 5, -2, 3, 6, -4]
# Ottieni numeri positivi univoci
positive_numbers = {n for n in numbers if n > 0}
print(positive_numbers) # Output: {1, 3, 5, 6}34.4.4) Quando le set comprehension sono più utili
Le set comprehension sono particolarmente preziose quando:
- Hai bisogno di valori univoci: rimuove automaticamente i duplicati
- L’ordine non conta: i set sono non ordinati, quindi usali quando la sequenza non è importante
- Eseguirai operazioni tra set: il risultato può essere usato con unione, intersezione, ecc. (come abbiamo visto nel Capitolo 17)
# Iscrizioni degli studenti a due corsi
course_a = ["Alice", "Bob", "Charlie", "David"]
course_b = ["Charlie", "David", "Eve", "Frank"]
# Ottieni studenti univoci in entrambi i corsi usando una set comprehension
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) Scegliere tra comprehension e cicli
34.5.1) Quando le comprehension sono migliori
Le comprehension sono generalmente preferite quando stai creando una nuova collezione trasformando o filtrando una collezione esistente. Sono più concise, spesso più leggibili e tipicamente più veloci dei cicli equivalenti.
Le comprehension eccellono quando:
- Crei una nuova collezione a partire da una esistente:
# Buon uso di una comprehension
prices = [10.99, 25.50, 8.75, 15.00]
discounted = [price * 0.9 for price in prices]- La trasformazione è semplice:
# Chiaro e conciso
names = ["alice", "bob", "charlie"]
uppercase_names = [name.upper() for name in names]- Filtri basandoti su condizioni semplici:
# Facile da capire
scores = [85, 92, 78, 65, 88, 55, 73, 95]
passing = [score for score in scores if score >= 70]34.5.2) Quando i cicli tradizionali sono migliori
Tuttavia, ci sono situazioni in cui i cicli tradizionali sono più appropriati e leggibili:
Usa i cicli quando:
- La logica è complessa o prevede più passaggi:
# Troppo complesso per una comprehension
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})Anche se potresti scriverlo come comprehension, sarebbe molto più difficile da leggere.
- Devi eseguire azioni oltre alla creazione di una collezione:
# Il ciclo è più chiaro quando si eseguono I/O o side effect
for filename in files:
with open(filename) as f:
content = f.read()
print(f"Processing {filename}")
# ... more processing- Devi modificare una collezione esistente in place:
# Modifica di una lista in-place - non si può usare una comprehension
numbers = [1, 2, 3, 4, 5]
for i in range(len(numbers)):
numbers[i] *= 2
print(numbers) # Output: [2, 4, 6, 8, 10]- Devi usare break o continue con logica complessa:
# Trovare la prima occorrenza con elaborazione aggiuntiva
found = None
for item in items:
if item.startswith("target"):
found = item
print(f"Found: {found}")
break34.5.3) Considerazioni sulla leggibilità
Il fattore più importante è la leggibilità. Se una comprehension diventa troppo lunga o complessa, trasformala in un ciclo tradizionale:
# Difficile da leggere - troppe cose in una sola riga
result = [item.upper().strip() for item in items if len(item) > 5 and item.startswith('a')]
# Meglio - usa un ciclo quando la logica è complessa
result = []
for item in items:
if len(item) > 5 and item.startswith('a'):
cleaned = item.strip().upper()
result.append(cleaned)Una buona regola pratica: se la tua comprehension non entra comodamente in una riga (o al massimo due righe con una formattazione chiara), valuta di usare un ciclo invece.
34.5.4) Considerazioni sulle prestazioni
Le comprehension sono generalmente più veloci dei cicli equivalenti perché sono ottimizzate a livello di interprete. Tuttavia, questa differenza di prestazioni è di solito trascurabile per collezioni piccole o medie.
# Entrambe producono lo stesso risultato
# La comprehension è leggermente più veloce
squares_comp = [n ** 2 for n in range(1000)]
# Il ciclo è leggermente più lento ma più flessibile
squares_loop = []
for n in range(1000):
squares_loop.append(n ** 2)Per la maggior parte degli scopi pratici, scegli in base alla leggibilità piuttosto che alle prestazioni. Ottimizza per la velocità solo se il profiling mostra che una particolare operazione è un collo di bottiglia.
34.5.5) Combinare gli approcci
A volte la soluzione migliore combina entrambi gli approcci:
# Usa una comprehension per una trasformazione semplice
student_data = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78}
]
# Estrai i punteggi con una comprehension
scores = [student["score"] for student in student_data]
# Usa un ciclo per elaborazioni complesse
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) Cicli annidati e più clausole for
34.6.1) Comprendere più clausole for
Le comprehension possono includere più clausole for, equivalenti a cicli annidati. La sintassi è:
[expression for item1 in iterable1 for item2 in iterable2]Questo è equivalente a:
result = []
for item1 in iterable1:
for item2 in iterable2:
result.append(expression)Il punto chiave è che le clausole for si leggono da sinistra a destra, proprio come i cicli annidati si scrivono dall’alto verso il basso.
Iniziamo con un esempio semplice che crea tutte le combinazioni di due liste:
# Due liste di valori
colors = ["red", "blue"]
sizes = ["S", "M", "L"]
# Crea tutte le combinazioni
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')]Questo crea ogni possibile abbinamento tra un colore e una taglia.
34.6.2) Creare coppie di coordinate
Un caso d’uso comune è generare coppie di coordinate:
# Crea una griglia 3x3 di coordinate
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)]Creare una tabella di moltiplicazione:
# Genera le coppie di moltiplicazione
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) Appiattire liste annidate
Più clausole for sono utili per appiattire strutture annidate:
# Lista annidata di numeri
nested_numbers = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Appiattisci in una singola lista
flat = [num for sublist in nested_numbers for num in sublist]
print(flat) # Output: [1, 2, 3, 4, 5, 6, 7, 8, 9]Questo è equivalente a:
flat = []
for sublist in nested_numbers:
for num in sublist:
flat.append(num)Appiattire una lista di parole in caratteri:
# Lista di parole
words = ["cat", "dog", "bird"]
# Ottieni tutti i caratteri di tutte le parole
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) Aggiungere condizioni alle comprehension annidate
Puoi aggiungere condizioni per filtrare i risultati:
# Crea coppie in cui la somma è pari
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)]Trovare elementi in comune tra liste:
# Due liste di numeri
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
# Trova i valori comuni (elementi in comune)
common = [x for x in list1 for y in list2 if x == y]
print(common) # Output: [4, 5]Nota: per trovare elementi in comune, usare l’intersezione tra set è più efficiente: set(list1) & set(list2), che abbiamo visto nel Capitolo 17.
34.6.5) Dictionary comprehension annidate
Puoi anche usare più clausole for nelle dictionary comprehension:
# Crea un dizionario delle somme delle coordinate
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) Quando evitare comprehension annidate
Anche se le comprehension annidate sono potenti, possono diventare rapidamente difficili da leggere. Considera queste linee guida:
Accettabile - relativamente semplice:
# Due livelli di annidamento, espressione semplice
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]]Sta diventando complesso - considera un ciclo:
# Tre livelli di annidamento - difficile da leggere
result = [[[i + j + k for k in range(2)] for j in range(2)] for i in range(2)]
# Better as nested loops for clarityRegola pratica: se hai più di due clausole for, o se l’espressione è complessa, usa invece cicli annidati tradizionali:
# Più chiaro con cicli espliciti
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)Le comprehension con più clausole for sono strumenti potenti, ma ricorda: la chiarezza è più importante della brevità. Se una comprehension annidata diventa difficile da capire, è meglio usare cicli espliciti.