2.12. Cicli

Un ciclo esegue ripetutamente lo stesso blocco di codice. Python ne ha due forme: while, che continua finché una condizione rimane vera, e for, che percorre gli elementi di una sequenza.

Diagrammi di flusso affiancati. while: verifica la condizione, esegue il corpo se vera, ripete. for: prende l'elemento successivo dal l'iterabile, esegue il corpo, ripete finché non è esaurito.

while continua a verificare una condizione; for percorre una sequenza finché non è esaurita.

2.12.1. Cicli while

Un ciclo while verifica la sua condizione prima di ogni iterazione ed esegue il corpo finché la verifica diventa falsa:

count = 0
while count < 5:
    print(count)
    count += 1

Output:

0
1
2
3
4

Se la condizione è vera all’inizio e non diventa mai falsa, il ciclo viene eseguito all’infinito. while True: è l’idioma standard per un ciclo principale, da cui si esce esplicitamente con break:

while True:
    step()
    if done():
        break

2.12.2. Cicli for

Un ciclo for percorre gli elementi di un iterabile – una lista, una tupla, una stringa, un oggetto bytes, un dizionario o qualsiasi altra cosa che supporti l’iterazione:

for fruit in ["apple", "banana", "cherry"]:
    print(fruit)

Output:

apple
banana
cherry

La stessa forma funziona su una stringa, dove ogni elemento è una stringa di un solo carattere:

for letter in "OpenMV":
    print(letter)

Output:

O
p
e
n
M
V

Iterare direttamente un dizionario produce le sue chiavi, nell’ordine di inserimento:

for key in {"a": 1, "b": 2}:
    print(key)

Output:

a
b

A ogni passaggio la variabile del ciclo (fruit, letter, key) viene associata all’elemento successivo. Al termine del ciclo, la variabile conserva il valore dell’ultima iterazione.

2.12.3. range

Per i cicli su un intervallo numerico, usa range():

  • range(stop) – 0, 1, …, stop - 1.

  • range(start, stop) – start, start + 1, …, stop - 1.

  • range(start, stop, step) – con un passo personalizzato (i valori negativi contano all’indietro).

for i in range(5):           # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 8, 2):     # 2, 4, 6
    print(i)

for i in range(10, 0, -1):   # 10, 9, ..., 1
    print(i)

range() produce i valori in modo pigro – non costruisce una lista in memoria. Per ottenere una vera list, racchiudilo: list(range(10)).

2.12.4. enumerate

Quando il ciclo ha bisogno sia dell’indice sia dell’elemento, enumerate() produce coppie (index, item):

for i, name in enumerate(["a", "b", "c"]):
    print(i, name)
# 0 a
# 1 b
# 2 c

Fai partire l’indice da un valore diverso da zero passando un secondo argomento: enumerate(items, start=1).

2.12.5. zip

Per percorrere due (o più) iterabili in parallelo, usa zip(). Produce una tupla per ogni posizione e si ferma all’input più corto:

names  = ["alice", "bob", "carol"]
scores = [88, 92, 70]

for name, score in zip(names, scores):
    print(name, score)

Output:

alice 88
bob 92
carol 70

2.12.6. Assegnazione inline con :=

L’operatore walrus := è un’assegnazione che è anche un’espressione. Associa un nome e valuta lo stesso valore nello stesso momento. In un ciclo while, questo riduce a una sola riga il comune schema «leggi, controlla, corpo»:

# without walrus
value = next_value()
while value is not None:
    process(value)
    value = next_value()

# with walrus
while (value := next_value()) is not None:
    process(value)

Le due forme fanno la stessa cosa. Ricorri a := quando la duplicazione dell’assegnazione danneggia davvero la leggibilità; non usarlo solo per essere ingegnosi. Le parentesi sono richieste nella maggior parte delle posizioni per mantenere l’espressione non ambigua.