Software in pratica – Parte 3 – Cicli, ovvero ripetere le operazioni


INDICE


LOOP

Per eseguire automaticamente un certo numero di volte una o più istruzioni (o anche l’intero programma) è indispensabile un’istruzione in grado di creare i cosiddetti loop, cicli o anelli, che vengono appunto utilizzati per eseguire più volte le istruzioni inserite al loro interno.

Vediamo come è formato un loop: il suo inizio è composto dall’istruzione while, seguita  da una condizione (come per if) e dai due punti. Sotto al while si scrivono indentate di 4 spazi le istruzioni da ripetere interne al loop. Queste istruzioni vengono ripetute continuamente fintanto che la condizione specificata continua a risultare vera. La struttura generale di un loop è pertanto:

while condizione:
    istruzione 1
    istruzione 2
    istruzione n

Rappresentazione grafica:

Flowchart ciclo while

Nota: se la condizione di controllo del ciclo risulta falsa già dall’inizio, le istruzioni all’interno del ciclo non vengono eseguite neppure una volta.

Vediamo subito un esempio che mostra come creare un loop con un numero specifico di ripetizioni (passaggi, iterazioni):


i = 1
while i <= 10:
    print("SERVI DELLA PLEBE")
    i = i + 1

Flowchart ciclo while

Questo programma stampa per 10 volte la scritta “SERVI DELLA PLEBE” (i computer sono servi della plebe). La variabile i è usata come contatore di ciclo (o variabile di controllo del ciclo o variabile sentinella) e viene incrementata di uno ad ogni iterazione. Quando raggiunge il valore 11 il ciclo termina e il programma prosegue con le eventuali istruzioni successive non indentate.

Ecco un altro esempio che mostra l’utilità di usare i cicli per analizzare automaticamente grandi quantità di dati. Vogliamo stampare quali sono i numeri fino a 600 divisibili esattamente per 37:


i = 1
while i <= 600:
    if i%37 == 0:
        print(i, end=" ")
    i = i + 1

Risultato:

37 74 111 148 185 222 259 296 333 370 407 444 481 518 555 592

 

ANNIDAMENTO

Anche le strutture iterative while possono essere annidate a piacere una dentro l’altra.

Ogni programma è sempre formato da blocchi di istruzioni sequenziali “incastonati” in strutture condizionali (if) e iterative (while) che ne stabiliscono l’ordine di esecuzione (flusso).

Questo tipo di organizzazione dei programmi, che fa uso di sole strutture sequenziali, condizionali e iterative (oltre alla scrittura ben indentata dei blocchi interni alle strutture), fa parte di un insieme di regole di buona programmazione che prende il nome di programmazione strutturata.

La programmazione strutturata permette non solo di ottenere programmi con meno errori, ma anche di scrivere listati (listing) facilmente comprensibili sia ad altre persone sia a voi stessi quando li rileggerete dopo molto tempo.

A proposito dei loop nei loop, se i cicli che realizzate fanno uso di una variabile di controllo del ciclo, bisogna fare attenzione a non modificare nei cicli interni la stessa variabile usata dal ciclo esterno, ad esempio provate a far girare questo programma:


#---------- PROGRAMMA CICLI (ERRATO)
h = 1
while h <= 10:
    print("PASSAGGIO ESTERNO NUMERO", h)
    h = 1
    while h <= 3:
        print("   PASSAGGIO INTERNO NUMERO", h)
        h = h + 1
    h = h + 1

Idealmente dovrebbe essere formato da un ciclo di 10 ripetizioni che contiene un ciclo di 3 ripetizioni (ripetuto appunto 10 volte). Però l’esecuzione non termina mai (e sarete costretti ad interrompere il programma con CONTROL + C), infatti il ciclo interno modifica il valore della variabile h usata anche da quello esterno, e la condizione di termine di quello esterno non arriva mai. È un esempio di side effect (effetto collaterale) dovuto alla modifica involontaria di variabili che non dovrebbero essere modificate in altri punti se non dove è richiesto farlo.

Se invece ogni ciclo usa una propria variabile di controllo indipendente, tutto funziona regolarmente come nell’esempio seguente.

In questo esempio facciamo anche una “parametrizzazione” del funzionamento, specificando con due variabili il numero di cicli esterni e interni che devono essere effettuati.

Queste variabili per convenzione sono scritte in maiuscolo per indicare che verranno usate come costanti all’interno del programma (il valore delle costanti non si modifica mai).

Le costanti si usano come dei “nomi di comodo” per rappresentare dei valori in diversi punti del programma, senza cospargerlo di “numeri magici” di cui non solo si dimenticherebbe facilmente il significato, ma, volendoli modificare, si rischierebbe di dimenticarne qualcuno, e trovare l’errore sarebbe molto difficile.


#---------- PROGRAMMA CICLI (CORRETTO)
C_EST = 3  # numero cicli esterni
C_INT = 2  # numero cicli interni
h = 1
while h <= C_EST:
    print("PASSAGGIO ESTERNO NUMERO", h)
    i = 1
    while i <= C_INT:
        print("   PASSAGGIO INTERNO NUMERO", i)
        if  h == C_EST  and  i == C_INT:
            print("   EHI! QUESTO E` L'ULTIMO!!!")
        i = i + 1
    h = h + 1

Risultato:

PASSAGGIO ESTERNO NUMERO 1
   PASSAGGIO INTERNO NUMERO 1
   PASSAGGIO INTERNO NUMERO 2
PASSAGGIO ESTERNO NUMERO 2
   PASSAGGIO INTERNO NUMERO 1
   PASSAGGIO INTERNO NUMERO 2
PASSAGGIO ESTERNO NUMERO 3
   PASSAGGIO INTERNO NUMERO 1
   PASSAGGIO INTERNO NUMERO 2
   EHI! QUESTO E` L'ULTIMO!!!

Flowchart esempio cicli nidificati

 

CICLI FLOATING POINT

Premetto che non è una buona pratica di programmazione, ma con una piccola attenzione potete anche creare cicli con numeri con la virgola, ad esempio per far assumere alla variabile di controllo tutti i valori compresi tra 5.0 e 6.0 a passi di 0.1 potete usare questo sistema:


c = 5.0
while round(c, 1) <= round(6.0, 1):
    print(round(c,1))
    c = c + 0.1

Questo programmino stampa esattamente 11 righe:

5.0
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
6.0

La piccola attenzione è l’uso della funzione round, in questo caso a un decimale (che arrotonda appunto a una cifra decimale), sul valore di c. Questo è necessario perché i numeri floating point non possono essere rappresentati con precisione assoluta, e quindi ripetuti incrementi di 0.1 accumulano un piccolo errore ad ogni ciclo, la cosa non causa normalmente alcun problema (Python ha una precisione di 16 cifre, almeno pari se non superiore a quella di una comune calcolatrice scientifica), ma in un confronto di uguaglianza questo piccolo errore ha la sua importanza dato che 50.000000000000441 risulterebbe diverso da 50.0

 

TRUE E BREAK

Spesso è utile creare un ciclo senza fine (che si ripete continuamente), da cui eventualmente uscire con un’ apposita istruzione di terminazione solo al verificarsi di una certa condizione.

Nel prossimo esempio il programma inizia con un ciclo while senza fine, che ha come condizione il valore True (che rappresenta una condizione sempre vera). L’unico modo per uscire da un ciclo come questo e’ usare l’istruzione break all’interno di esso.

Quando viene incontrata una break l’esecuzione del ciclo termina immediatamente, e il programma prosegue con le righe successive che non fanno parte del blocco di istruzioni del ciclo stesso:


while True:
    b = int(input("QUANTO TI PIACE PYTHON (DA 1 A 10) ?"))
    if b <= 10:
        break
    print("GRAZIE MA E` TROPPO")
while b > 0:
    print("W PYTHON")
    b = b - 1

Risultato:

QUANTO TI PIACE PYTHON (DA 1 A 10) ?12
GRAZIE MA E` TROPPO
QUANTO TI PIACE PYTHON (DA 1 A 10) ?8
W PYTHON
W PYTHON
W PYTHON
W PYTHON
W PYTHON
W PYTHON
W PYTHON
W PYTHON

Nel primo ciclo viene chiesto un valore compreso tra 1 e 10, se si immette un valore superiore a 10 appare la scritta “GRAZIE MA E` TROPPO” e viene chiesta di nuovo l’immissione. Altrimenti il ciclo termina e inizia il secondo, che stampa per b volte la scritta inneggiante a Python.

Cercate di fare buon uso dei loop e sforzatevi di inventare qualsiasi cosa esca dalla vostra fulgida mente, ma soprattutto cercate di seguire passo passo le singole righe di programma immedesimandovi nel computer che le deve eseguire, e cercate di capire cosa deve accadere in ogni situazione verificandolo in pratica.


INDICE


Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *