Basi

Cicli e condizioni in Python: for, while, range, enumerate, break, if/elif e match/case

Aggiornato: · Skillaria.Top

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.

ChiamataNumeri
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 for ne salta alcuni. Meglio costruire una nuova lista: clean = [x for x in items if x > 0].
  • Limite di range. range(1, n) non include n.
  • 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

  1. Calcolate la somma e la media di una lista di spese, saltando i valori negativi.
  2. Stampate la tabellina da 1 a 9 con cicli annidati.
  3. Chiedete all'utente dei numeri finché non inserisce una riga vuota, poi stampate il massimo.
  4. Trovate il primo numero maggiore di 1000 in una lista e segnalate se non c'è (con for ... else).
  5. Analizzate i comandi add, del, list con match.

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.

Impara l’argomento in video

Questo argomento è trattato in modo approfondito, con pratica, nel corso «Python 3.15: от новичка до профи».

Vai al corso