Hai mai scritto uno script Python che fa esattamente una cosa, dall’inizio alla fine, sempre uguale? Funziona, certo — ma è come un navigatore che conosce una sola strada: al primo cantiere si blocca. Il salto di qualità arriva quando il tuo programma comincia a decidere: se il file esiste aprilo, altrimenti crealo; per ogni riga del dataset controlla il valore; finché l’utente non scrive «esci», continua a chiedere. Questo è il controllo di flusso, e in Python si regge su tre parole chiave — if, for, while — più un’arma segreta tutta pythonica: le comprehension.
Tipi, strutture dati, controllo di flusso e funzioni: le basi di Python sono nel libro, in un percorso che si legge in ordine.
Prerequisiti minimi: sai eseguire uno script Python 3.12 (se non ricordi come, ti basta un terminale con python script.py dentro un ambiente creato con python -m venv .venv o, più moderno, uv venv) e sai cosa sono liste e stringhe — le abbiamo viste nell’articolo precedente della serie. Tutto il resto lo costruiamo qui.
if: il bivio
Pensa a if come al bivio di una strada: il programma arriva, guarda il cartello (la condizione), e prende una direzione sola. L’analogia quotidiana perfetta è il buttafuori di un locale: guarda il documento, e se hai l’età giusta entri, altrimenti no. Non esiste il «forse»: una condizione in Python è sempre True o False.
# Il buttafuori digitale
eta = 17
if eta >= 18:
print("Benvenuto!") # eseguito solo se la condizione è vera
elif eta >= 16:
print("Solo fino alle 22.") # controllato solo se la prima è falsa
else:
print("Torna tra qualche anno.")
Nota due cose. Primo: l’indentazione (i quattro spazi) non è estetica, in Python è la sintassi — il blocco indentato è ciò che viene eseguito. Secondo: elif viene valutato solo se le condizioni precedenti sono false, quindi l’ordine conta. Se avessi messo eta >= 16 per prima, un diciottenne verrebbe trattato da sedicenne.
Python considera «falsi» anche valori che non sono letteralmente False: la lista vuota [], la stringa vuota "", lo zero, None. Per questo vedrai spesso if risultati: invece di if len(risultati) > 0: — dice la stessa cosa, con meno rumore.
for: il nastro trasportatore
Il ciclo for è un nastro trasportatore in una fabbrica: gli oggetti passano uno alla volta davanti a te, e su ciascuno esegui la stessa operazione. Non ti chiedi «a che posizione sono arrivato?»: prendi il prossimo pezzo finché il nastro non si svuota. In Python il for itera direttamente sugli elementi, non sugli indici — è la differenza più grande rispetto a linguaggi come C o Java.
# Controllo qualità su un batch di misure
misure = [12.1, 11.8, 47.9, 12.3, 12.0, 11.9]
SOGLIA = 20.0
anomalie = []
for valore in misure: # 'valore' assume un elemento alla volta
if valore > SOGLIA:
anomalie.append(valore) # accumulo i fuori soglia
print(f"Trovate {len(anomalie)} anomalie: {anomalie}")
# Trovate 1 anomalie: [47.9]
Questo pattern — parti da un contenitore vuoto, cicli, accumuli — lo userai centinaia di volte: è il cuore della pulizia dati prima di dare in pasto qualsiasi cosa a scikit-learn. Se invece ti serve un ciclo «a conteggio» (fai qualcosa 10 volte), usi range: for i in range(10): genera i numeri da 0 a 9, uno alla volta, senza mai costruire la lista intera in memoria.
while: il termostato
Il for va bene quando sai su cosa iterare. Ma se non sai in anticipo quante volte? Pensa a un termostato: non scalda «per 7 cicli», scalda finché la temperatura non raggiunge quella desiderata. Questo è while: ripeti finché la condizione resta vera.
# Discesa verso un obiettivo: dimezzo l'errore finché non è abbastanza piccolo
errore = 100.0
passi = 0
while errore > 0.1: # condizione controllata PRIMA di ogni giro
errore = errore / 2 # se dimentichi questa riga: loop infinito!
passi += 1
print(f"Convergenza in {passi} passi, errore finale {errore:.4f}")
# Convergenza in 10 passi, errore finale 0.0977
Ti sembra un giochino? È lo scheletro concettuale della discesa del gradiente: ripeti un aggiornamento finché l’errore non scende sotto una tolleranza. Ogni training loop che scriverai in futuro è un while (o un for sulle epoche) travestito. Attenzione al rischio classico: se dentro il ciclo non modifichi mai la condizione, il programma gira per sempre. Due parole chiave ti danno controllo fine: break esce subito dal ciclo, continue salta al giro successivo.
Un programma senza controllo di flusso è una lista della spesa. Con if, for e while diventa una ricetta: assaggia, aggiusta, ripeti finché non è pronto.
Il flowchart di un loop, una volta per tutte
Fissiamo visivamente cosa succede a ogni giro di un ciclo con condizione. Questo schema vale identico per il while ed è, concettualmente, quello che for fa dietro le quinte (la condizione implicita è «ci sono ancora elementi?»).
Il flowchart di un loop: la condizione fa da cancello. Se è vera si esegue il corpo, si aggiorna lo stato e si torna al cancello; se è falsa si esce. Dimenticare l’aggiornamento significa non uscire mai.
Le comprehension: il ciclo in una riga
Ora l’arma segreta. Ricordi il pattern «contenitore vuoto + for + append»? Python lo comprime in un’unica espressione leggibile: la list comprehension. È come ordinare al bar «un caffè macchiato» invece di dettare la ricetta passo passo: stesso risultato, comunicato in un colpo solo.
misure = [12.1, 11.8, 47.9, 12.3, 12.0, 11.9]
# Versione classica: 4 righe
quadrati = []
for m in misure:
if m < 20:
quadrati.append(m ** 2)
# Versione comprehension: 1 riga, stesso identico risultato
quadrati = [m ** 2 for m in misure if m < 20]
# Funziona anche per dizionari e set
etichette = {m: ("ok" if m < 20 else "anomalia") for m in misure}
print(quadrati)
print(etichette[47.9]) # anomalia
Si legge così, da sinistra: «costruisci una lista di m**2, per ogni m in misure, ma solo se m < 20«. Nelle pipeline di machine learning le comprehension sono ovunque: filtrare feature, trasformare etichette, costruire vocabolari.
Onestà intellettuale, però: le comprehension non servono sempre. Se dentro il ciclo hai più condizioni annidate, effetti collaterali (scritture su file, print) o più di una trasformazione, il buon vecchio for esplicito è più leggibile — e la leggibilità in Python vince sempre. Una comprehension che devi rileggere tre volte è un ciclo scritto male, non codice elegante. Stesso discorso per i loop in generale: se stai ciclando su numeri per fare matematica elemento per elemento, quasi sempre esiste un’operazione NumPy vettorizzata che fa la stessa cosa cento volte più veloce. Il controllo di flusso è il fondamento, non il martello per ogni chiodo.
Prova tu
Esercizio concreto: scrivi uno script fizzbuzz_dati.py che, data la lista temperature = [18.5, 21.0, 35.2, -3.0, 22.1, 40.5, 19.9], (1) usi un for con if/elif/else per classificare ogni valore in «gelo» (sotto 0), «normale» (0–30) o «allarme» (sopra 30); (2) riscriva la stessa classificazione come dict comprehension {valore: classe}; (3) usi un while che rimuova il valore massimo dalla lista finché la media non scende sotto 20 (ti serve sum(lista)/len(lista) e lista.remove(max(lista))). Se i tre output sono coerenti tra loro, hai capito il controllo di flusso.
Per approfondire: il capitolo «More Control Flow Tools» del tutorial ufficiale di Python copre anche match, il «fratello strutturale» di if introdotto in Python 3.10; e il capitolo 2 di Fluent Python (Luciano Ramalho, 2ª edizione) è la lettura definitiva sulle comprehension fatte bene.

I commenti sono riservati agli iscritti.
Accedi per commentare