# Python: comprendere e utilizzare il ciclo for

Il ciclo for in Python, “for loop” in inglese, viene utilizzato per **eseguire ripetutamente un blocco di codice**. I cicli for sono una parte fondamentale della maggior parte dei linguaggi di programmazione. Vi mostriamo come funziona il ciclo for su Python e come utilizzarlo.

## Cos’è il ciclo for su Python?

Oltre all’istruzione if-else, il ciclo for è probabilmente la struttura di programmazione più conosciuta. Generazioni di studentesse e studenti si sono scervellate sul concetto informatico di **ciclo**, in quanto **inizialmente non risulta molto intuitivo**. Tuttavia, i problemi di comprensione possono derivare più che altro dal modo in cui il materiale viene presentato. Di per sé, infatti, i cicli non sono nulla di eccezionale.

Vi illustriamo il concetto di ciclo con un esempio. Immaginiamo una classe delle elementari. **L’insegnante vuole determinare l’altezza media delle bambine e dei bambini con un esperimento**. Per farlo, chiede a ogni bambina e bambino la loro altezza e somma le singole altezze per ottenere un totale. Poi divide la somma per il numero degli alunni della classe per ricavare l’altezza media. Astraiamo un semplice algoritmo dalla procedura dell’insegnante:

1. Richiesta dell’altezza di ciascun bambino e bambina e aggiunta al totale corrente
2. Divisione della somma per il numero di alunni della classe

Il primo passaggio viene eseguito una volta per ogni bambino e bambina e **dipende quindi dal numero di studenti nella classe**. Il secondo viene eseguito una sola volta, indipendentemente dalle dimensioni della classe. Abbiamo bisogno di un ciclo per il primo passaggio. Di seguito riportiamo quindi un esempio di codice che calcola l’altezza media di un bambino o una bambina della scuola con un ciclo for su Python:

```none
children_heights = [155, 171, 148, 161, 158, 153, 162]
height_sum = 0
for height in children_heights:
    height_sum = height_sum + height
average_height = height_sum // len(children_heights)
print(average_height)
```

Il ciclo for su Python esegue ripetutamente un blocco di codice. Questa operazione viene anche definita “iterazione”. In particolare, i cicli consentono a diversi **elementi** combinati in un “insieme” di essere **elaborati singolarmente secondo lo stesso schema**. Si usa un ciclo for quando la dimensione dell’insieme può essere determinata in fase di esecuzione del programma. In caso contrario, di solito si utilizza un ciclo while.

Consiglio Imparate da soli a scrivere nel codice Python grazie al nostro [tutorial su Python](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/tutorial-python/ "Tutorial Python").

## Cosa distingue il ciclo for su Python dagli altri linguaggi?

Molti linguaggi di programmazione conoscono il concetto di ciclo for. Oltre che in Python, è una **struttura di base** anche in altri linguaggi come C, Java, JavaScript e PHP. I linguaggi puramente funzionali come Haskell o Lisp di solito riescono a fare a meno di un ciclo for esplicito. Al posto dell’iterazione, in questi linguaggi si utilizzano funzioni ricorsive.

Tutti i cicli hanno in comune il fatto che un blocco di codice viene eseguito ripetutamente. Tuttavia, il **meccanismo d’azione del ciclo for in Python differisce notevolmente** da quello di altri linguaggi. Ad esempio, la maggior parte dei linguaggi di programmazione utilizza una cosiddetta variabile di ciclo che viene incrementata o decrementata durante l’esecuzione del ciclo.

<table>
  <thead>
    <tr>
      <th>Operazione</th>
      <th>Significato</th>
      <th>Sintassi convenzionale</th>
      <th>Sintassi Python</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Incremento</td>
      <td>Aumenta il valore di una variabile intera di una quantità specifica e fissa</td>
      <td>i++</td>
      <td>index += 1</td>
    </tr>
    <tr>
      <td>Decremento</td>
      <td>Diminuisce il valore di una variabile intera di una quantità specifica e fissa</td>
      <td>i--</td>
      <td>index -= 1</td>
    </tr>
  </tbody>
</table>

Vediamo un esempio di come funziona un ciclo for in altri linguaggi. **Con un ciclo for, produciamo i numeri da 0 a 9 in JavaScript**. Definiamo una variabile intera “number” e la incrementiamo finché il numero in essa contenuto è inferiore a 10. Il codice utilizzato a questo scopo sembra piuttosto criptico per i nuovi arrivati:

```none
for ( let number = 0; number < 10; number++ ) {
    console.log(number);
}
```

Il codice per un **ciclo for corrispondente in Python** appare molto più ordinato:

```none
for number in range(10):
    print(number)
```

Invece di fornire direttamente il valore della variabile del ciclo, di solito viene utilizzato per **indicizzare un elemento all’interno di un insieme**. Di nuovo, prima un esempio in JavaScript: produciamo i nomi contenuti nell’elenco “people” uno dopo l’altro. Utilizziamo la variabile del ciclo ‘i’ come indice progressivo dei singoli elementi:

```none
people = ['Jack', 'Jim', 'John']
for (let i = 0; i < people.length; i++) {
    console.log("Here comes " + people[i]);
}
```

L’indicizzazione diretta di elementi successivi dell’elenco deve essere trattata con cautela. Questo perché un tentativo di accesso al di fuori dei limiti consentiti provoca un errore di runtime. Di norma, si tratta del famoso “off-by-one error”. Python dimostra che si può procedere in modo diverso. Qui vi proponiamo lo stesso esempio con un ciclo for su Python, in cui **iteriamo direttamente gli elementi dell’elenco** senza indicizzarli con una variabile del ciclo:

```none
people = ['Jack', 'Jim', 'John']
for person in people:
    print(f"Here comes {person}")
```

L’uso indiretto della variabile del ciclo contribuisce a creare molta confusione quando si imparano i cicli for in altri linguaggi. Questo perché di solito **non siamo interessati alla variabile centrale del ciclo**. Viene utilizzata solo per indicizzare i singoli elementi. L’uso dei cicli for convenzionali richiede la comprensione di diverse questioni complesse. Vediamone un esempio con JavaScript:

<table>
  <thead>
    <tr>
      <th>Argomento</th>
      <th>Occorrenza nel ciclo for di JavaScript</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Assegnazione delle variabili</td>
      <td>let i = 0</td>
    </tr>
    <tr>
      <td>Espressioni booleane</td>
      <td>i &lt; limit</td>
    </tr>
    <tr>
      <td>Operatore di incremento o decremento</td>
      <td>i++ / i--</td>
    </tr>
    <tr>
      <td>Determinazione delle dimensioni di un insieme</td>
      <td>i &lt; list.length</td>
    </tr>
    <tr>
      <td>Indicizzazione degli elementi basata su zero</td>
      <td>i &lt; list.length ist OK; i &lt;= list.length führt zu Off-by-one Error</td>
    </tr>
  </tbody>
</table>

Per chiarire meglio, vediamo il risultato delle singole lettere di una parola. All’interno del ciclo for, una lettera della parola viene resa disponibile nella variabile “letter” per ogni passaggio del ciclo. Questo **funziona senza una variabile di ciclo** e quindi senza il rischio di produrre un errore off-by-one. Il codice è preciso e di facile lettura:

```none
word = "Python"
for letter in word:
    print(letter)
```

## Come funziona un ciclo for in Python?

Come abbiamo visto, il ciclo for su Python risolve elegantemente il problema dell’**iterazione degli elementi di un insieme**. Possiamo farlo senza deviazioni attraverso una variabile numerica di ciclo. È sicuramente una buona cosa, ma come funziona esattamente? Per comprendere il principio di funzionamento del ciclo for in Python, è necessario conoscere i concetti di iterabile e iteratore.

### Cosa sono l’iterabile, l’iteratore e il generatore?

Il **ciclo for in Python opera su oggetti noti come “iterabili”**. In questo caso si tratta di stringhe, liste, tuple e altri tipi di dati composti. Usando le parole della documentazione ufficiale di Python:

Citazione “\[An iterable is\] an object capable of returning its members one at a time” - Fonte: https://docs.python.org/3/glossary.html#term-iterable

Traduzione: “\[Un iterabile è\] un oggetto che ha la capacità di restituire i suoi membri uno alla volta” (tradotto da IONOS).

Un **oggetto iterabile** ha due proprietà:

1. Raggruppa diversi elementi in un insieme.
2. Garantisce l’accesso agli elementi tramite un’interfaccia chiamata “iteratore”.

Nel complesso, ciò significa che gli iterabili sono insiemi il cui contenuto può essere iterato. In particolare, un iterabile ha un metodo “\_\_iter\_\_()” che restituisce un iteratore. L’iteratore è un **oggetto che restituisce l’elemento successivo dell’iterabile su comando**. Inoltre, un iteratore ricorda la posizione dell’ultimo elemento restituito all’interno dell’insieme.

<table>
  <thead>
    <tr>
      <th>Funzione</th>
      <th>Spiegazione</th>
      <th>Esempio</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>iter(collection)</td>
      <td>Richiama il metodo \_\_iter\_\_() dell’insieme</td>
      <td>it = iter(“Python”)</td>
    </tr>
    <tr>
      <td>next(iter)</td>
      <td>Richiama il metodo \_\_next\_\_() dell’iteratore</td>
      <td>next(it)</td>
    </tr>
    <tr>
      <td>collection\[index\]</td>
      <td>Richiama il metodo \_\_getitem\_\_(index) dell’insieme</td>
      <td>‘Python’\[1\]</td>
    </tr>
  </tbody>
</table>

Un iteratore restituisce l’elemento successivo quando viene richiamato il metodo \_\_next\_\_(). Se **tutti gli elementi dell’insieme sono stati consegnati, l’iteratore è esaurito**. Un’altra chiamata a \_\_next\_\_() attiva un’eccezione “StopIteration”.

Vediamo **come funziona un iteratore con un esempio**. Creiamo un oggetto range() che rappresenta i numeri consecutivi da 21 a 23. Successivamente, creiamo un iteratore con la funzione iter() e otteniamo gli elementi successivi con la funzione next(). Con l’ultima chiamata, viene avviata l’eccezione perché l’iteratore è esaurito:

```none
numbers = range(21, 24)
number = iter(numbers)
next(number)
# returns `21`
next(number)
# returns `22`
next(number)
# returns `23`
next(number)
# raises `StopIteration` exception
```

Un iteratore consente di accedere ai singoli elementi di un insieme. Python conosce anche il concetto correlato di “generatore”. La differenza è che un **generatore crea i singoli elementi solo quando vi si accede**. In questo modo si risparmia spazio in memoria durante l’esecuzione del programma; questa operazione viene definita anche “lazy generation”.

Un generatore in Python si basa su una funzione che utilizza l’istruzione yield. Simile all’istruzione return, **restituisce un oggetto e termina la chiamata di funzione**. Quando viene richiamata, tuttavia, la funzione generatore non riparte dall’inizio, ma continua dopo l’ultima istruzione yield.

Vediamo un esempio. Scriviamo la nostra **implementazione della funzione range()**. Per farlo, utilizziamo l’istruzione yield all’interno di un ciclo while per generare numeri progressivi:

```none
def my_range(start, stop):
    if stop < start:
        return None
    current = start
    while current < stop:
        yield current
        current += 1
# test
assert list(my_range(7, 9)) == list(range(7, 9))
```

### Saltare e annullare un ciclo for in Python

In pratica, a volte è necessario saltare un singolo passaggio del ciclo. Come molti altri linguaggi, Python contiene l’istruzione continue. Quando viene **richiamato continue all’interno del corpo del ciclo, l’iterazione corrente viene interrotta**. Il ciclo inizia immediatamente l’iterazione successiva.

L’istruzione continue **può essere utilizzata in modo simile a quella Early Return in una chiamata di funzione**. Ad esempio, saltiamo un’iterazione non appena stabiliamo che un set di dati non ha la qualità richiesta:

```none
def process_data(data):
    for data_set in data:
        data_set.validate()
        # early continue after cheap check fails
        if not data_set.quality_ok():
            continue
        # expensive operation guarded by early continue
        data_set.process()
```

Un altro esempio. Produciamo un testo e **saltiamo tutte le lettere in seconda posizione**:

```none
text = 'Skipping every second letter'
for index, letter in enumerate(text):
    if index % 2 != 0 and letter != ' ':
        continue
    print(letter)
```

L’istruzione break viene spesso utilizzata per implementare algoritmi di ricerca. Se un elemento cercato è stato trovato all’interno di un ciclo, non è necessario iterare ulteriormente. Analogamente alla funzione any(), controlliamo un elenco per verificare la presenza di un singolo valore true. Interrompiamo con break non appena abbiamo trovato qualcosa:

```none
bool_list = [False, False, True, False]
for index, boolean in enumerate(bool_list):
    if boolean:
        print(f"Value at position {index + 1} is True")
        print(f"Aborting inspection of remaining {len(bool_list) - index - 1} item(s)")
        break
```

In relazione all’istruzione break, un ciclo for in Python può essere **dotato di un corpo opzionale else**. Il codice che contiene viene eseguito quando il ciclo termina senza che sia stata eseguita un’istruzione break:

```none
def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you're looking for")
            break
    else:
        print("Didn't find what you were looking for")
# test
find_element('a', 'Python')
find_element('o', 'Python')
```

I cicli for sono spesso utilizzati in Python all’interno dei corpi delle funzioni. In questo caso, è comune **utilizzare un’istruzione return invece di una break**. Il nostro algoritmo di ricerca si riformula senza l’uso di break ed else:

```none
def find_element(target, collection):
    for element in collection:
        if element == target:
            print("Found what you're looking for")
            # returning breaks us out of the loop
            return element
    # we made it here without returning
    print("Didn't find what you were looking for")
    return None
# test
print(find_element('a', 'Python'))
print(find_element('o', 'Python'))
```

## Quali sono le migliori pratiche per i cicli for in Python?

I cicli for in Python sono usati principalmente per **iterare gli elementi di una sequenza o di un insieme**. Inoltre, per molti casi d’uso comuni esistono metodi più diretti. Vi presentiamo le migliori pratiche principali e anti-pattern. Innanzitutto, un riepilogo dei termini centrali:

<table>
  <thead>
    <tr>
      <th>Termine</th>
      <th>Spiegazione</th>
      <th>Esempio</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Insieme</td>
      <td>Riassunto di più elementi. Un insieme è un iterabile</td>
      <td>(‘Walter’, ‘White’), \[4, 2, 6, 9\], ‘Python’</td>
    </tr>
    <tr>
      <td>Iteratore</td>
      <td>Interfaccia per iterare gli insiemi</td>
      <td>it = iter(‘Python’)</td>
    </tr>
    <tr>
      <td>Generatore</td>
      <td>Una funzione che utilizza yield al posto dell’istruzione return. Un generatore è un iterabile</td>
      <td>range(10)</td>
    </tr>
    <tr>
      <td>Comprensione</td>
      <td>Espressione iterante; genera un nuovo insieme basato su un iterabile</td>
      <td>\[num \*\* 2 for num in range(10)\]</td>
    </tr>
  </tbody>
</table>

### Iterazione diretta degli elementi di un insieme

Un **errore comune dei programmatori Python inesperti** è l’uso improprio del ciclo for in Python. Come è comune in altri linguaggi, si usa la funzione len() come limite di quella range() per creare una variabile numerica del ciclo. In questo modo indicizzate i singoli elementi dell’insieme:

```none
word = 'Python'
for i in range(len(word)):
    print(word[i])
```

Questo anti-pattern è **disapprovato in quanto non è considerato in linea con la sintassi di Python** per una buona ragione. Infatti, è meglio iterare direttamente gli elementi dell’insieme con il ciclo for in Python:

```none
word = 'Python'
for letter in word:
    print(letter)
```

### Enumerare gli elementi di un insieme con enumerate() includendo l’indice

A volte **è necessario l’indice di un elemento all’interno dell’insieme**. Invece di creare l’indice come variabile del ciclo, utilizziamo la funzione [enumerate()](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/python-enumerate/). Viene così restituita la tupla (indice, elemento). Si noti che l’indice inizia a contare da zero:

```none
names = ["Jim", "Jack", "John"]
for index, name in enumerate(names):
    print(f"{index + 1}. {name}")
```

### Iterazione di tuple di elementi con la funzione zip()

Un altro scenario comune è quello di **iterare contemporaneamente gli elementi di due insiemi di uguale lunghezza**. L’approccio di Python utilizza la funzione zip(), prendendo due insiemi di uguale lunghezza e restituendo 2 tuple successive:

```none
people = ('Jim', 'Jack', 'John')
ages = (42, 69, 13)
# ascertain both collections are same length
assert len(people) == len(ages)
# iterate over tuples of (person, age)
for person, age in zip(people, ages):
    print(f"{person} is {age} years old")
```

### Creazione di una variabile di ciclo numerica con la funzione range()

Normalmente, i cicli for vengono utilizzati in Python per iterare gli elementi di un insieme. L’**incremento di un intero con un ciclo for** è un caso particolare in Python. Il modo corretto è quello di costruire un oggetto range con la funzione range() e iterarlo:

```none
for counter in range(10):
    print(counter)
```

### Usare l’operatore in per verificare se un insieme contiene un elemento

Trovare un elemento particolare all’interno di un insieme fa parte del repertorio standard di un programmatore o di una programmatrice. Normalmente, si utilizza una funzione che itera gli elementi, **verificando l’uguaglianza di ciascun elemento con quello cercato**. Se l’elemento viene trovato, l’iterazione viene interrotta.

In Python, per questo caso comune esiste l’operatore in. L’operatore **verifica se l’insieme contiene l’elemento cercato** e restituisce un valore booleano corrispondente:

```none
'a' in 'Python'
'y' in 'Python'
```

### Utilizzo della funzione list() per creare un elenco da un iterabile

A differenza di molti altri linguaggi, in Python non è necessario utilizzare un ciclo for per **scrivere le lettere di una stringa una per una in un elenco**. Si usa invece la funzione list() per convertire un iterabile in un elenco di elementi. Analizziamo entrambi gli approcci con un esempio. Iteriamo le lettere di una parola e le aggiungiamo a un elenco vuoto:

```none
word = 'Python'
letters = []
for letter in word:
    letters.append(letter)
```

Possiamo risparmiarci la fatica. **Creiamo l’elenco direttamente con la funzione list()**. Allo stesso tempo, verifichiamo con l’asserzione assert che entrambi i metodi diano lo stesso risultato:

```none
assert list(word) == letters
```

Un altro esempio. **Creiamo un elenco di numeri da zero a nove**. Un oggetto range serve come base per un iterabile:

```none
list(range(10))
```

Oltre agli elenchi, a partire da un iterabile si possono creare anche dei **set**. Ad esempio, creiamo un set che restituisce le lettere contenute in una frase. Con l’operatore in verifichiamo che il set delle lettere non contenga una ‘a’:

```none
alphabet = set('Python is not hyped')
assert 'a' not in alphabet
```

## Sostituire i cicli for in Python con le comprensioni

Un uso comune dei cicli for in Python è quello di modificare gli elementi di un insieme. Potremmo voler **calcolare nuovi valori in base a un insieme** o filtrare alcuni elementi in base a un modello. Seguendo lo stile di programmazione imperativo, descriviamo i singoli passaggi nel modo seguente:

1. Iterare l’insieme con un ciclo for
2. Elaborare ogni elemento
3. Se necessario, combinare un sottoinsieme di elementi in un nuovo insieme

Per le modifiche semplici, è piuttosto complesso. I linguaggi funzionali dimostrano che è possibile farlo in modo più semplice. Fortunatamente, Python conosce il concetto di “comprensione” (“comprehension” in inglese). Le comprensioni possono sostituire **semplici applicazioni del ciclo for in Python**. Sono più performanti di applicazioni equivalenti di un ciclo for.

Una **comprensione crea un insieme modificato basato su un iterabile**. Per farlo, viene utilizzata una sintassi concisa ed espressiva. Vediamo la sintassi generale della comprensione di una lista. Scriviamo l’espressione tra parentesi quadre. Viene eseguita un’operazione sugli elementi di un insieme; ogni elemento viene copiato in un nuovo elenco:

```none
[ operation(element) for element in collection ]
```

Inoltre, gli **elementi possono essere filtrati in base a determinati modelli**. Vengono utilizzati un if opzionale e una condizione:

```none
[ operation(element) for element in collection if condition(element) ]
```

Vediamo ora un esempio di **ciclo for in Python che può essere sostituito da una comprensione**. Abbiamo un elenco di numeri e vogliamo calcolare il corrispondente elenco di numeri quadrati:

```none
numbers = [2, 3, 5, 9, 17]
```

**Creiamo un elenco vuoto e lo riempiamo** con i quadrati **all’interno di un ciclo for**:

```none
squares = []
for number in numbers:
    squares.append(number ** 2)
```

**L’elenco dei numeri quadrati** può essere espresso più semplicemente **sotto forma di comprensione**:

```none
squares_comp = [number ** 2 for number in numbers]
```

Utilizziamo quindi l’istruzione assert per assicurarci che **entrambi i metodi restituiscano lo stesso risultato**:

```none
assert squares == squares_comp
```

Un altro esempio. Desideriamo **estrarre le lettere minuscole da una stringa**. Creiamo un elenco di lettere sia maiuscole che minuscole da inserire:

```none
word = list("PyThoN")
```

Il modo convenzionale per estrarre le lettere minuscole è quello di iterare le lettere. **Verifichiamo ogni lettera con la funzione islower()** e la aggiungiamo a un elenco inizialmente vuoto se il risultato è positivo:

```none
lowers = []
for letter in word:
    if letter.islower():
        lowers.append(letter)
```

Possiamo risparmiarci questo ciclo for in Python. Utilizziamo invece una **comprensione** che copia solo le lettere minuscole dell’elenco originale:

```none
lowers_comp = [ letter for letter in word if letter.islower() ]
```

Anche in questo caso, **verifichiamo l’uguaglianza dei due metodi** utilizzando l’istruzione assert:

```none
assert lowers == lowers_comp
```


This is a markdown version of: [https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/ciclo-for-su-python/](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/ciclo-for-su-python/) for AI/LLM consumption.