2.30. Comprehension¶
Una comprehension costruisce una nuova lista, set, dict o generatore a partire da un iterabile esistente, in un’unica espressione. È un sostituto del pattern comune che parte da un contenitore vuoto e aggiunge elementi in un ciclo.
2.30.1. List comprehension¶
squares = [x * x for x in range(5)]
print(squares)
Output:
[0, 1, 4, 9, 16]
Lo stesso ciclo scritto per esteso:
squares = []
for x in range(5):
squares.append(x * x)
La forma a comprehension è un’unica espressione che costruisce la lista sul posto. Non c’è alcun squares = [] e nessun .append – il risultato è il valore della comprehension.
L’espressione iniziale produce ogni elemento; la clausola for nomina la variabile di ciclo; una clausola if opzionale filtra via gli elementi.¶
2.30.2. Filtrare con if¶
Una clausola if opzionale mantiene solo gli elementi che corrispondono:
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
Output:
[0, 2, 4, 6, 8]
Il filtro viene eseguito prima dell’espressione iniziale – x % 2 == 0 viene verificato per primo; solo i valori corrispondenti raggiungono x per l’output.
2.30.3. Dict e set comprehension¶
La stessa struttura funziona con i letterali dict e set.
Una dict comprehension ha una coppia key: value prima del for:
squares = {x: x * x for x in range(5)}
print(squares)
Output:
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Una set comprehension usa le parentesi graffe e un’unica espressione:
unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)
Output:
{1, 2}
2.30.4. Espressioni generatrici¶
Le parentesi tonde producono un”espressione generatrice anziché una lista. I valori vengono calcolati uno alla volta, su richiesta:
total = sum(x * x for x in range(1000))
Non viene mai costruita alcuna lista da un milione di elementi. I valori fluiscono uno per uno in sum(), che li somma e scarta ciascuno man mano che procede.
Le espressioni generatrici sono la scelta giusta quando si alimentano valori in una funzione di riduzione (sum(), max(), any(), all()) o in qualsiasi altro codice che consuma iteratori – risparmiano la memoria che la lista equivalente avrebbe utilizzato.
2.30.5. Quando non usare una comprehension¶
Le comprehension sono concise ma non sempre più chiare. Ricorri a un semplice ciclo for quando:
Il corpo necessita di più di un’istruzione (una comprehension contiene esattamente un’espressione).
Il corpo ha effetti collaterali (stampa, scrittura su file) – le comprehension servono a costruire una collezione, non a eseguire azioni.
Il filtro o la trasformazione ha così tante parti che la comprehension non si legge più da sinistra a destra.