I cicli - O dell'arte di ripetersi!

Contenuto del capitolo
Come usare i cicli per ridurre le parti ripetitive. I differenti tipi di cicli e come usarli.

Nell'ultimo esercizio abbiamo visualizzato una parte della tavola pitagorica del 12. Ma è stato necessario parecchio lavoro di battitura e se fosse necessario estenderla dovremmo perdere ancora altro tempo. Fortunatamente c'è un modo migliore per farlo e qui cominceremo a comprendere la vera potenza dei linguaggi di programmazione.

I cicli FOR

Adesso vedremo come utilizzare il linguaggio di programmazione per effettuare le ripetizioni, facendo uso di una variabile che viene incrementata ad ogni ripetizione. In Python tutto questo si può esprimere cosí:

>>>for i in range(1,13):
...    print "%d x 12 = %d" % (i, i*12)
...

Nota 1: si utilizza range(1,13) per specificare il numero 12 perché la funzione range() genera una sequenza di numeri a partire dal primo fino al secondo, non incluso. Questo fatto a prima vista può sembrare bizzarro ma c'è una ragione che sarà chiara in seguito. .

Nota 2: L'operatore for in Python è in effetti un operatore foreach in quanto applica la sequenza di operazioni che lo segue a ciascun membro di una collezione. La collezione in questo caso è la lista di numeri generata da range(). Potete verificarlo scrivendo print range(1,13) al prompt di Python ed osservando il risultato.

Nota 3: la linea print è scritta indentata verso destra rispetto alla linea for che la precede. Questo è un dettaglio assai importante perché è questo che iin Python specifica quale è la porzione di programma da ripetere. Non importa di quanto le linee siano indentate, purché lo siano tutte della stessa quantità.

Nota 4: Usando l'interprete in modo interattivo è necessario premere il tasto INVIO due volte per mandare il programma in esecuzione. Ciò è dovuto al fatto che l'interprete Python non può sapere se dopo il primo INVIO segue un'altra linea che deve essere aggiunta alle istruzioni del ciclo oppure no. Quando si preme INVIO per la seconda volta, allora è chiaro che le istruzioni sono terminate e possono essere eseguite.

Come funziona dunque il programma? Procediamo passo passo.
Prima di tutto Python usa la funzione range() per creare una lista di numeri da 1 a 12.

Poi Python assegna ad i il primo valore preso dalla lista, in questo caso 1. Subito dopo esegue la parte di programma scritta indentata, usando il valore i = 1:

   print "%d x 12 = %d" % (1, 1*12)

Python quindi torna alla linea for ed assegna ad i il valore successivo nella lista, cioè 2. Quindi esegue nuovamente la parte di programma indentata, questa volta con i = 2:

   print "%d x 12 = %d" % (2, 2*12)

Questa sequenza di operazioni viene ripetuta fino a che non sono esauriti i valori della lista. A questo punto Python passa ad eseguire la prima linea successiva non indentata; in questo caso non ci sono altre istruzioni e quindi il programma si arresta.

Ecco lo stesso ciclo in BASIC:

FOR I = 1 to 12
    PRINT I, " x 12 = ", I*12
NEXT I

Questa forma è più esplicita ed è più facile da comprendere. Però la versione Python è più flessibile in quanto è possibile iterare su un insieme di numeri, sugli elementi di una lista e su qualunque tipo di collezione (ad esempio una lista di stringhe).

Ed in Tcl

Tcl usa un costrutto for modellato su quello del linguaggio C, comune a molti altri linguaggi di programmazione. Ha la forma seguente:

for {set i 1} {$i <= 12} {incr i} {
    puts [format "%d x 12 = %d" $i [expr $i*12]]
    }

Nota: Questo costrutto è fatto di tre parti:

Il corpo del ciclo viene eseguito esclusivamente se la parte di test ha valore vero. Ciascuna delle tre parti può contenere qualunque istruzione, ma la parte di test deve avere come risultato un valore booleano (che in Tcl significa zero o non-zero). Notate che anche se il corpo del ciclo è indentato questo serve solo a scopo di maggior leggibilità. Tcl non richiede di scrivere il blocco indentato ed utilizza invece le parentesi graffe per delimitare i blocchi.

Tcl ha anche un costrutto foreach che può essere applicato alle liste.

Cicli WHILE

I cicli FOR non sono l'unico tipo di costrutto disponibile per le iterazioni. Questo sarebbe limitativo perché in un ciclo FOR è necessario conoscere, o poter calcolare, in anticipo il numero di iterazioni che si devono effettuare. Cosa si può fare invece quando vogliamo continuare ad eseguire un gruppo di istruzioni fino a che non si verifica una qualche condizione, ma non conosciamo in precedenza quando ciò può accadere? Supponiamo ad esempio di voler leggere ed analizzare i dati di un file senza sapere in anticipo quanti dati sono contenuti nel file. In questo caso è necessario proseguire con le operazioni fino a raggiungere la fine del file. Questo è possibile, ma non facile da fare con un ciclo FOR.

Per risolvere questo problema disponiamo di un altro tipo di ciclo: il ciclo WHILE. In BASIC si presenta cosí:

J = 1
WHILE J <= 12
    PRINT J, " x 12 = ", J*12
    J = J + 1
WEND

Questo produce lo stesso risultato mostrato prima, ma usa il ciclo while invece del for. Notate che la struttura è composta da while, seguito da una espressione che ha come risultato un valore Booleano (vero o falso, come già detto). Se l'espressione ha valore vero, viene eseguito il codice all'interno del ciclo.

Vediamo come alternativa la versione Tcl:

set j  1
while {$j <= 12} {
   puts [format "%d x 12 = %s"  $j [expr $j*12]]
   set j [expr $j + 1]
}

Come vedete la struttura è assai simile, usa solo alcune parentesi graffe invece del WEND del BASIC. Ma cosa rappresenta la complessa istruzione all'interno del ciclo? Ricordate le stringhe di formato in Python? format è l'equivalente in Tcl. Il $j significa semplicemente 'il valore di j' (e non: la lettera 'j'!) ed expr significa "considera la porzione che segue come un'espressione da calcolare". Le parentesi quadre indicano in Tcl quali parti della linea devono essere eseguite per prime. Tcl è un linguaggio inusuale perché cerca di interpretare il codice in una sola passata, quindi senza le parentesi cercherebbe di visualizzare la parola 'expr' e successivamente trovando alcuni altri valori terminerebbe con un codice di errore. Dobbiamo essere noi a specificare di calcolare le somme, poi di formare la stringa, poi di visualizzare il risultato. Vi sembra complicato? Non ve ne preoccupate. Come già detto Tcl è un linguaggio inusuale con alcune caratteristiche specifiche assai buone e parecchie stranezze.

Diamo ora uno sguardo a Python:

>>> j = 1
>>> while j <= 12:
...    print "%d x 12 = %d" % (j, j*12)
...    j = j + 1

A questo punto il programma dovrebbe risultarvi abbastanza semplice. C'è solo una cosa da notare; il carattere (:) alla fine delle linee while e for che abbiamo visto. Questo ha il solo scopo di indicare che sta per seguire un blocco di codice. La maggior parte dei linguaggi hanno un simbolo di fine blocco (come WEND in BASIC e le parentesi graffe in Tcl) ma Python usa la scrittura indentata per indicare la struttura del programma. Questo significa che è importante che tutte le istruzioni del corpo di un ciclo siano indentate della stessa quantità, e questa è comunque una buona pratica in quanto il programma risulta più facile da leggere!

Cicli più flessibili

Torniamo adesso alla tabellina che abbiamo visto all'inizio del capitolo. Il ciclo che abbiamo creato va benissimo per la tabellina del dodici. Ma cosa accade per altri valori? Possiamo modificare il ciclo per visualizzare, diciamo, la tabellina del sette? dobbiamo fare più o meno cosí:

>>> for j in range(1,13):
...    print "%d x 7 = %d" % (j,j*7)

Abbiamo dovuto cambiare due volte un 12 in un 7. E se volessimo un'altra tabellina ancora dovremmo cambiarli di nuovo. Non sarebbe meglio se potessimo specificare il moltiplicatore che vogliamo?

Possiamo farlo sostituendo i valori nella stringa dell'istruzione print con un'altra variabile e poi assegnando il valore alla variabile prima del ciclo:

>>> moltiplicatore = 12
>>> for j in range(1,13):
...    print "%d x %d = %d" % (j, moltiplicatore, j*moltiplicatore)

Questa è la tabellina del dodici che ci è familiare. Ma adesso per trasformarla nella tabellina del sette dobbiamo solo cambiare il valore di 'moltiplicatore'.

Notate che abbiamo combinato una sequenza di istruzioni con un ciclo. Abbiamo infatti prima una istruzione singola moltiplicatore = 12 seguita in sequenza da un ciclo for.

Cicli che ciclano

Riprendiamo ora l'esempio precedente e avanziamo ancora di un passo. Supponiamo di voler visualizzare tutte le tabelline da quella del due a quella del dodici (evitiamo quella dell'uno che è banale). Dobbiamo solo sistemare la variabile moltiplicatore all'interno di un altro ciclo, cioè:

>>> for moltiplicatore in range(2,13):
...    for j in range(1,13):
...       print "%d x %d = %d" % (j,moltiplicatore,j*moltiplicatore)

Notate che la parte indentata che segue il primo ciclo for è identica al ciclo che abbiamo visto subito sopra. Il tutto funziona come segue:
Viene assegnato a moltiplicatore il primo valore (2) e quindi si passa ad eseguire il ciclo più interno.
Finito questo si assegna a moltiplicatore il secondo valore (3) e di nuovo si esegue il ciclo interno,
e cosí via. Questa tecnica viene chiamata nidificazione dei cicli.

Rimane un piccolo inconveniente: tutte le tabelline vengono visualizzate di seguito, ma possiamo risolverlo semplicemente facendo scrivere al programma una linea di separazione alla fine del primo ciclo, cosí:

>>> for moltiplicatore in range(2,13):
...    for j in range(1,13):
...       print "%d x %d = %d" % (j,moltiplicatore,j*moltiplicatore)
...    print "------------------- "

Notate che la seconda istruzione print è allineata con la seconda istruzione 'for', e quindi rappresenta la seconda istruzione nella sequenza che costituisce il corpo del primo ciclo. Non dimenticate che l'indentazione è fondamentale in Python.

Potete ulteriormente sperimentare facendo in modo che il separatore indichi quale tabellina lo segue, trasformandolo cosí in una didascalia. Suggerimento: dovrete utilizare la variabile moltiplicatore ed una stringa di formato.

Altri cicli

Altri linguaggi forniscono altri tipi di costrutti per i cicli ma di solito qualche forma di for e di while la troverete sempre. (Modula 2 e Oberon hanno solo i cicli while in quanto con questi si possono simulare cicli for come abbiamo visto sopra.) Altri cicli che potrete incontrare sono:

do-while
Come il while, ma il test viene fatto alla fine.
repeat-until
Simile a quello sopra,ma la logica del test viene invertita.
GOTO, JUMP, LOOP etc
Si trovano principalmente nei linguaggi piu "antichi", di solito stabiliscono un segnale in un punto del codice e "saltano" esplicitamente a tale punto.
Punti da ricordare
  • I cicli FOR ripetono un insieme di istruzioni per un numero fisso di volte.
  • I cicli WHILE ripetono un insieme di istruzioni fino a che non si verifica una determinata condizione. Il corpo del ciclo non viene eseguito nemmeno una volta se la condizione è falsa fino dall'inizio.
  • Esistono altri tipi di cicli, ma il ciclo FOR ed il ciclo WHILE sono quasi sempre disponibili.
  • In Python i cicli for sono in relatà cicli di tipo foreach: operano su una lista di elementi.
  • I cicli possono essere nidificati uno dentro l'altro.

Precedente  Successivo  Indice


Se avete domande o suggerimenti relativi a questa pagina mandate un e-mail all'autore: alan.gauld@yahoo.co.uk o al traduttore italiano: lfini@arcetri.astro.it