List Comprehension
Impara la sintassi delle list comprehension in Python, il filtraggio, i cicli annidati, le dict e set comprehension con esempi eseguibili.
List Comprehension in Python
La list comprehension è un modo conciso per costruire una nuova lista applicando un'espressione a ogni elemento di un iterabile — con la possibilità di filtrare gli elementi tramite una condizione — il tutto in una singola riga leggibile. Questa pagina copre la sintassi completa, i pattern più comuni, le dict e set comprehension, e indica quando un semplice ciclo for è la scelta migliore.
Sintassi
La forma generale di una list comprehension è:
new_list = [expression for item in iterable if condition]| Parte | Ruolo |
|---|---|
expression | Valore inserito nella nuova lista per ogni item |
item | Variabile di ciclo, assume ogni valore dall'iterable in sequenza |
iterable | Qualsiasi sequenza o iterabile: lista, tupla, string, range, ecc. |
if condition | Filtro opzionale — vengono inclusi solo gli elementi dove la condizione è True |
La parte if condition è opzionale. Se omessa, ogni elemento dell'iterabile produce un'entrata nella nuova lista.
Esempio Base: Calcolo dei Quadrati
Il ciclo for equivalente richiede tre righe; la list comprehension fa lo stesso in una sola:
Filtraggio con una Condizione
Aggiungi una clausola if dopo l'iterabile per mantenere solo gli elementi che soddisfano una condizione:
Puoi combinare qualsiasi predicato. Ad esempio, mantenere le parole più lunghe di quattro caratteri:
words = ['hi', 'hello', 'world', 'python', 'ai']
long_words = [w for w in words if len(w) > 4]
print(long_words) # ['hello', 'world', 'python']if/else nell'Espressione (Ternario)
Quando hai bisogno di trasformare ogni elemento ma applicare logica diversa in base a una condizione, inserisci if/else all'interno della parte espressione (prima di for), non dopo l'iterabile:
numbers = range(1, 6)
labels = ['even' if x % 2 == 0 else 'odd' for x in numbers]
print(labels) # ['odd', 'even', 'odd', 'even', 'odd']Nota la differenza:
[expr for x in it if cond]— filtro: salta gli elementi dovecondèFalse[a if cond else b for x in it]— trasformazione: ogni elemento produce un valore, scelto dacond
Lavorare con le Stringhe
La list comprehension funziona su qualsiasi iterabile, incluse le stringhe e le liste di stringhe:
words = ['hello', 'world', 'python']
upper_words = [w.upper() for w in words]
print(upper_words) # ['HELLO', 'WORLD', 'PYTHON']Estrai i singoli caratteri che soddisfano una condizione:
vowels = [ch for ch in 'programming' if ch in 'aeiou']
print(vowels) # ['o', 'a', 'i']Cicli Annidati
La list comprehension supporta più clausole for, equivalenti a cicli annidati. Il for più a sinistra è il ciclo esterno:
Un caso d'uso comune per le list comprehension annidate è appiattire una lista 2D (matrice) in una lista 1D:
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [n for row in matrix for n in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]Suggerimento di lettura: espandi mentalmente le comprehension annidate come cicli for annidati nello stesso ordine da sinistra a destra.
Dictionary Comprehension
La stessa idea si applica ai dizionari usando {} con un'espressione key: value:
keys = ['a', 'b', 'c']
values = [1, 2, 3]
mapping = {k: v for k, v in zip(keys, values)}
print(mapping) # {'a': 1, 'b': 2, 'c': 3}Scambia chiavi e valori in un dizionario esistente:
original = {'name': 'Alice', 'city': 'Paris'}
inverted = {v: k for k, v in original.items()}
print(inverted) # {'Alice': 'name', 'Paris': 'city'}Set Comprehension
Usa {} con una singola espressione (senza i due punti) per costruire un set, che rimuove automaticamente i duplicati:
numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {x ** 2 for x in numbers}
print(unique_squares) # {1, 4, 9, 16}Il risultato è non ordinato (i set non hanno un ordine garantito), quindi non fare affidamento sulla sequenza stampata.
Prestazioni
Le list comprehension sono generalmente più veloci dei cicli for equivalenti che chiamano .append() perché l'interprete può ottimizzare il ciclo interno in C. Per misurare i tempi del tuo codice, usa il modulo timeit:
import timeit
loop_time = timeit.timeit(
'result = []\nfor x in range(1000):\n result.append(x**2)',
number=10000
)
comp_time = timeit.timeit(
'[x**2 for x in range(1000)]',
number=10000
)
print(f'Loop: {loop_time:.3f}s')
print(f'Comprehension: {comp_time:.3f}s')
# Comprehension is typically 20-40% fasterIl vantaggio prestazionale si riduce o scompare quando l'espressione stessa è lenta (I/O di rete, calcoli pesanti). Esegui il profiling prima di ottimizzare.
Quando Usare un Ciclo for Semplice
La list comprehension non è sempre lo strumento giusto:
| Situazione | Preferire |
|---|---|
| Singola trasformazione o filtro | List comprehension |
| Effetti collaterali multipli per iterazione (logging, modifica dello stato) | Ciclo for |
| Logica complessa che richiede più istruzioni | Ciclo for |
| Comprehension profondamente annidate (più di due livelli) | Ciclo for — la leggibilità vince |
| Il risultato non viene mai memorizzato (occorre solo iterare) | Generator expression ((x for x in ...)) |
Il segnale più chiaro per tornare a un ciclo for è quando ti ritrovi a fissare la comprehension per capire cosa fa.
Errori Comuni
Le variabili non "fuoriescono" in Python 3. La variabile di ciclo in una comprehension è limitata all'ambito della comprehension stessa:
x = 'original'
result = [x * 2 for x in range(3)]
print(x) # 'original' — not overwritten by the comprehension's xEvita le comprehension profondamente annidate. Più di due clausole for in una singola comprehension riduce la leggibilità con scarso beneficio. Suddividile in liste intermedie con nome o in cicli for.
Le generator expression risparmiano memoria. Se devi iterare sul risultato una sola volta (ad esempio, passarlo a sum() o max()), sostituisci [] con () per ottenere un generatore che produce un elemento alla volta:
total = sum(x ** 2 for x in range(1, 1001))
print(total) # 333833500