Cicli e condizioni in Python: for, while, range, enumerate, break, if/elif e match/case
I cicli in Python ripetono le azioni: for scorre gli elementi di una collezione o di un range(), mentre while continua finché la condizione è vera. Si può interrompere un ciclo con break, saltare un'iterazione con continue, numerare gli elementi con enumerate(). Le decisioni si prendono con if/elif/else, mentre la struttura match/case (da Python 3.10) serve a riconoscere i dati dalla loro forma.
I cicli in Python servono a ripetere un'azione: scorrere la lista della spesa, elaborare ogni riga di un file, chiedere all'utente un numero finché non ne inserisce uno corretto. Il linguaggio ha due cicli, for e while, e per prendere decisioni al loro interno si usano le condizioni if/elif/else e la struttura match/case. Vediamo ogni strumento con esempi pratici.
Condizioni: if, elif, else
L'istruzione condizionale esegue un blocco di codice solo se l'espressione è vera. Il blocco si delimita con un rientro di 4 spazi: in Python non ci sono parentesi graffe, e un rientro sbagliato genera subito IndentationError.
spent = 4200
limit = 5000
if spent > limit:
print("Limite superato")
elif spent > limit * 0.8:
print("Resta meno del 20% del budget")
else:
print("Tutto a posto")
I rami elif vengono controllati dall'alto verso il basso e si esegue solo il primo che corrisponde. Quindi le condizioni più restrittive vanno messe in alto: se la verifica spent > limit * 0.8 fosse la prima, il messaggio sul superamento del limite non comparirebbe mai.
Che cosa è considerato vero
Nella condizione non è obbligatorio scrivere un confronto. Sono considerati falsi False, None, lo zero (0, 0.0) e le collezioni vuote: "", [], {}. Tutto il resto è vero. Quindi la verifica «la lista non è vuota» si scrive in modo breve:
expenses = []
if not expenses:
print("Nessuna spesa per ora")
Le condizioni si combinano con and, or, not, e un intervallo si verifica comodamente con un confronto a catena: if 0 < amount <= 100_000:. Per una scelta breve di valore esiste l'operatore ternario: status = "alto" if spent > limit else "normale".
Il ciclo for in Python: sintassi ed esempi
Il ciclo for in Python non è un contatore come in C, ma un'iterazione sugli elementi. Prende in sequenza ogni elemento di un oggetto iterabile: lista, stringa, dizionario, file, range. È l'equivalente del foreach di altri linguaggi: in Python è semplicemente il for.
expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
total += amount
print(total) # 6139
Sintassi del ciclo for: for variabile in collezione:, seguito dal blocco con rientro. Dopo il ciclo la variabile conserva l'ultimo valore: a volte è utile, ma nei programmi grandi non conviene affidarsi a questo comportamento.
Ciclo su stringa, lista e dizionario
La stringa viene scorsa carattere per carattere, la lista elemento per elemento. Il ciclo su un dizionario scorre per impostazione predefinita le chiavi; per ottenere insieme chiave e valore si usa .items():
by_category = {"cibo": 3200, "trasporti": 900, "cinema": 600}
for category, amount in by_category.items():
print(f"{category}: {amount} €")
Per i soli valori c'è .values(). Non si può cambiare la dimensione del dizionario durante il ciclo: si ottiene RuntimeError: dictionary changed size during iteration. Se bisogna rimuovere elementi, scorrete una copia: for key in list(d):.
La funzione range: ciclo sui numeri
Quando serve scorrere dei numeri, si usa range(). Non crea una lista in memoria, ma restituisce i numeri uno alla volta, quindi range(10**9) funziona istantaneamente.
| Chiamata | Numeri |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 3) | 0, 3, 6, 9 |
range(5, 0, -1) | 5, 4, 3, 2, 1 |
La regola principale: il limite destro non è incluso. range(1, 10) termina con 9 — è una causa frequente dell'errore «di uno». Il passo può essere negativo, ma non può essere zero.
for i in range(1, 4):
print(f"Giorno {i}")
# Giorno 1
# Giorno 2
# Giorno 3
enumerate: contatore nel ciclo
I principianti scrivono spesso for i in range(len(items)) per conoscere il numero dell'elemento. Funziona, ma si legge peggio. La funzione enumerate() restituisce coppie «numero, elemento», e il parametro start stabilisce da quale numero partire:
items = ["caffè", "taxi", "pranzo"]
for n, item in enumerate(items, start=1):
print(n, item)
# 1 caffè
# 2 taxi
# 3 pranzo
Per scorrere in parallelo due liste c'è zip(): for name, price in zip(names, prices):. Si ferma alla lista più corta; dalla versione 3.10 si può passare strict=True, e in quel caso lunghezze diverse generano un errore.
Il ciclo while in Python
Il ciclo while ripete il blocco finché la condizione è vera. Si sceglie quando il numero di ripetizioni non è noto in anticipo: si attende un input corretto, si leggono dati fino alla fine, si ripete una richiesta fino al successo.
balance = 10_000
month = 0
while balance > 0:
balance -= 2_700
month += 1
print(f"I soldi bastano per {month} mesi") # 4
Il pericolo principale è dimenticare di modificare la variabile della condizione: il ciclo non finirebbe mai. Se il programma sembra bloccato, premete Ctrl+C: Python interrompe l'esecuzione con KeyboardInterrupt.
Ciclo infinito e il «do while»
A volte il ciclo infinito in Python si scrive di proposito: while True: con l'uscita tramite break. Lo stesso schema sostituisce il ciclo con controllo finale: in Python non esiste il costrutto do while, e lo si imita così — il corpo viene eseguito almeno una volta e la verifica sta alla fine.
while True:
raw = input("Importo: ")
if raw.isdigit():
amount = int(raw)
break
print("Inserite un numero intero")
Un ciclo for infinito è raro: succede solo se si scorre un iteratore senza fine, per esempio itertools.count().
break e continue: uscita dal ciclo e salto dell'iterazione
break interrompe subito il ciclo e l'esecuzione prosegue con il codice che segue. continue salta il resto dell'iterazione corrente e passa alla successiva.
expenses = [350, -10, 1200, 0, 99_999, 89]
for amount in expenses:
if amount <= 0:
continue # salta questa iterazione
if amount > 50_000:
print("Importo sospetto, stop")
break # esce dal ciclo
print(amount)
Verranno stampati 350 e 1200, poi il messaggio: il ciclo non arriva fino a 89. Entrambe le istruzioni agiscono solo sul ciclo più vicino in cui si trovano.
else nel ciclo
for e while hanno un ramo else insolito: viene eseguito se il ciclo è terminato da solo, senza break. È comodo per le ricerche:
for amount in expenses:
if amount > 50_000:
print("Trovata una spesa grande")
break
else:
print("Non ci sono spese grandi")
Cicli annidati
Un ciclo dentro un altro esegue quello interno per intero a ogni iterazione di quello esterno. Così si scorrono tabelle, matrici, si generano coppie.
for row in range(1, 4):
for col in range(1, 4):
print(row * col, end="\t")
print()
Due cose da ricordare. Primo: la complessità cresce in fretta, e due cicli annidati su 10 000 elementi significano 100 milioni di operazioni. Secondo: break esce solo dal ciclo interno. Per interrompere entrambi conviene mettere i cicli in una funzione e usare return: è più pulito dei flag.
L'istruzione match/case
La lunga catena if cmd == ... elif ... dalla versione 3.10 si può sostituire con match (PEP 634). Non è un semplice switch: confronta il valore con un modello basato sulla forma dei dati e separa subito le parti in variabili.
def parse(text):
match text.split():
case ["add", item, amount]:
return f"Aggiungi {item}: {amount}"
case ["list"] | ["ls"]:
return "Mostra le spese"
case ["quit"]:
return "Uscita"
case _:
return "Comando sconosciuto"
print(parse("add Caffè 250")) # Aggiungi Caffè: 250
print(parse("add Caffè")) # Comando sconosciuto
Il modello-lista ["add", item, amount] corrisponde solo a una lista di esattamente tre elementi, il primo dei quali è "add". Quindi un comando senza importo finisce nel ramo _, che cattura tutto il resto. Il simbolo | unisce le varianti.
Dizionari, tipi e condizione di guardia
Il modello-dizionario controlla solo le chiavi elencate, e quelle extra vengono ignorate. La scrittura int(a) verifica il tipo e cattura il valore, mentre un if dopo il modello aggiunge una condizione ulteriore (guard):
match event:
case {"type": "expense", "amount": int(a)} if a > 10_000:
print("Spesa grande", a)
case {"type": "expense", "amount": int(a)}:
print("Spesa", a)
La trappola principale di match
Un nome semplice in case è una cattura, non un confronto con una variabile. case limit: corrisponde a qualsiasi valore e lo scrive in limit. Per confrontare con costanti bisogna usare un nome puntato, per esempio case Color.RED:, oppure dei letterali.
La sintassi di match dalla 3.10 è rimasta quasi invariata. Nella Python 3.15 è stata eliminata una piccola asimmetria: nei modelli letterali prima era ammesso il meno davanti a un numero, ora si può scrivere anche case +1:. Nelle versioni più vecchie questo codice darà un errore di sintassi.
Errori tipici nei cicli
- Modifica della lista durante il ciclo. Rimuovere elementi dentro un
forne salta alcuni. Meglio costruire una nuova lista:clean = [x for x in items if x > 0]. - Limite di range.
range(1, n)non includen. - Dimenticare di modificare la condizione del while — ciclo infinito.
- Unire stringhe nel ciclo con +=: con grandi volumi è più lento di
"".join(parts). - Assegnazione al posto del confronto:
if x = 5è un errore di sintassi; il confronto si scrive con==.
Esercizi sui cicli
- Calcolate la somma e la media di una lista di spese, saltando i valori negativi.
- Stampate la tabellina da 1 a 9 con cicli annidati.
- Chiedete all'utente dei numeri finché non inserisce una riga vuota, poi stampate il massimo.
- Trovate il primo numero maggiore di 1000 in una lista e segnalate se non c'è (con
for ... else). - Analizzate i comandi
add,del,listconmatch.
Conclusioni
I cicli di Python si riducono a due costrutti: for scorre gli elementi di una collezione o di range(), while lavora finché la condizione è vera. break e continue governano il percorso del ciclo, enumerate() e zip() eliminano i contatori manuali, mentre if/elif/else e match/case si occupano delle decisioni. Tutti questi strumenti sono trattati in pratica sull'esempio del tracker delle spese nella lezione del corso dedicata a Python.
Domande frequenti
In che cosa differiscono for e while in Python?
for scorre una sequenza già pronta e sa da solo quando fermarsi, mentre while si ripete finché la condizione è vera. Se il numero di ripetizioni è noto o c'è una collezione, usate for; se aspettate un evento, usate while.
Come scorrere un ciclo al contrario?
Usate reversed(items) per una collezione oppure range(n - 1, -1, -1) per i numeri. La funzione reversed non copia la lista, ma la scorre partendo dalla fine.
Python ha lo switch?
Non esiste uno switch separato: il suo ruolo è svolto dalla catena if/elif e dall'istruzione match/case, comparsa in Python 3.10. match sa fare di più: scompone liste e dizionari in base alla forma e cattura i valori.
È più veloce un ciclo o una list comprehension?
La list comprehension del tipo [x * 2 for x in items] di solito è un po' più veloce del ciclo equivalente con append e più corta. Per logiche complesse con più condizioni il ciclo classico è più leggibile.
Come uscire da due cicli annidati contemporaneamente?
break interrompe solo il ciclo interno. La soluzione più semplice è spostare i cicli in una funzione e uscire con return.
Questo argomento è trattato in modo approfondito, con pratica, nel corso «Python 3.15: от новичка до профи».
Vai al corso