8: L'ISTRUZIONE while

I CICLI

Una delle caratteristiche di un computer è la velocità e le precisione nello svolgere azioni ripetitive: quello che annoierebbe a morte una persona umana, portandola a deconcentrarsi ed a sbagliare, viene fatto senza batter ciglio da un computer, che può ripetere un blocco di istruzioni miliardi di volte senza stancarsi. Nei linguaggi di programmazione ci sono sempre istruzioni per ottenere dei cicli (Inglese: loops).

Un ciclo è un blocco di istruzioni (sempre riconosciuto da Python per mezzo dell'indentazione) che può essere ripetuto più volte.

Il controllo su quante volte ripetere un ciclo sarà assunto da un'apposita istruzione di controllo di flusso, che determinerà quando si deve uscire dal ciclo (cioè continuare con le istruzioni successive). Se commettiamo uno sbaglio in questa istruzione, possiamo entrare in un ciclo senza fine (Inglese: "endless loop") cioè in un ciclo che si ripete all'infinito: è un comune errore di programmazione che fa in genere "inchiodare" il programma. Se questo ci accade in Python possiamo premere insieme Control C per terminare il programma "a forza bruta".

L'ISTRUZIONE while

NUOVO PROGRAMMA: prova_while.py

Aprite l'editor e digitate questo nuovo esempio (potete omettere i commenti, che servono solo a spiegarvi cosa fa il programma):


s = ""                            # stringa vuota: serve per inizializzare la variabile s
while s != "mamma":               # while con l'espressione di controllo
    s = input("Scrivi 'mamma' ")  # questo è il blocco da ripetere
print ("Bravo!")                  # qui si esce dal ciclo

Provate a lanciare il programma, che vi chiederà di scrivere "mamma". Scrivete per due o tre volte un'altra parola e vedrete che il programma continuerà a chiedervi la stessa cosa. Solo quando scriverete esattamente "mamma" (con tutte lettere minuscole) il programma vi dirà "Bravo!"

L'istruzione while permette di ripetere un blocco di linee finchè una condizione di controllo (espressione booleana) rimane vera. Quando il programma giunge al while valuta l'espressione: se essa è vera entra nel ciclo (cioè in una serie di linee indentate come nell'if); alla fine dell'indentazione ritorna al while e valuta di nuovo l'espressione: se essa è ancora vera riesegue il ciclo e così via. Quando l'espressione diventa falsa il programma esce dal ciclo e continua con la prima linea allo stesso livello di indentazione del while.

Quindi il programma funziona così: all'inizio si assegna a s la stringa vuota. Nella seconda riga il while si chiede se essa sia diversa da "mamma": poichè questo è vero il programma entra nel ciclo (cioè la terza riga indentata). Questa viene ripetuta finchè s è diversa da "mamma", e si esce dal solo quando la condizione di controllo diventa falsa (cioè quando s diventa uguale a "mamma").

Provate ad eliminare la prima riga: cosa succede? Otterrete un NameError perchè nell'espressione s != "mamma" Python trova la variabile s non ancora definita (ricordate questo). Provate invece a sostituire la prima riga con questa
s = "mamma":
adesso invece il programma scriverà direttamente "Bravo!": infatti il primo while trova falsa l'espressione booleana s != "mamma" e non entra per niente nel ciclo.

Prima di entrare in un ciclo while è necessario che le variabili che compaiono nella condizione di controllo siano già definite (altrimenti si ottiene un errore). Se all'entrata nel ciclo la condizione è falsa il ciclo viene completamente saltato.

NUOVO PROGRAMMA: risposta.py
ESERCIZIO 8.1: Scrivere un programma, simile al precedente, che chieda all'utente se vuole giocare ancora e lo saluti quando esce. Esempio di I/O (ricordate che l'output del programma è stampato in nero e le risposte dell'utente in blu):
Vuoi giocare ancora (s/n)? s
Vuoi giocare ancora (s/n)? s
Vuoi giocare ancora (s/n)? s
Vuoi giocare ancora (s/n)? n
Ciao!
SUGGERIMENTO: Create all'inizio una stringa risp = "s"
SOLUZIONI
NUOVO PROGRAMMA: indovina_numero.py

Il while e l'if ci permettono già di programmare un semplice giochino. Cercate per il momento di non usare ancora il copia-incolla: è opinione comune che scrivere le righe una per una faciliti la comprensione del programma; eventualmente potete saltare i commenti.


from random import *      # verra' spiegata in seguito

num = randrange(1, 21)    # questa istruzione genera un numero casuale da 1 a 20: dovremo indovinarlo
print ("Ho pensato un numero da 1 a 20. Prova ad indovinarlo!")
mio_num = -1              # inizializza mio_num ad un valore sicuramente diverso da num ...
while mio_num != num:     # ... quindi la prima volta entra sicuramente nel while
    mio_num = int(input("??? "))    # qui introduciamo il nostro tentativo (mio_num)
    if mio_num < num:
        print("Troppo basso")
    elif mio_num > num:
        print("Troppo alto")
print("Hai indovinato!")

Provate a lanciare il programma e ad indovinare il numero; cercate poi di capire qual è la funzione di ogni singola riga. Questo programma può essere usato come base per altri sviluppi:

ESERCIZIO 8.2: Modificare il programma in modo che alla fine della partita chieda se si vuole giocare ancora ed eventualmente ripeta il gioco. SUGGERIMENTO: è necessario incorporare tutte le istruzioni dalla num = randrange(1, 21) alla fine in un while esterno come quello implementato nell'esercizio 8.1. Per indentare molte linee in una sola volta conviene selezionarle con il mouse ed usare la voce di menu Format=>Indent Region.
ESERCIZIO 8.3: Modificare il programma in modo che ricordi il numero di tentativi effettuati e li scriva alla fine del gioco. SUGGERIMENTO: è necessaria una nuova variabile tentativi che va inizializzata a 0 prima del gioco ed incrementata di uno ad ogni tentativo. Attenti a dove dovete scrivere le istruzioni di inizializzazione e di incremento. All'uscita dal ciclo basta modificare l'istruzione print facendole scrivere anche il numero di tentativi.
ESERCIZIO 8.4: Modificare il programma in modo che ricordi il record di tentativi. SUGGERIMENTO: all'inizio del programma, subito dopo l'istruzione import, creare una variabile record inizializzandola ad un numero altissimo (es. record = 100000000). Dopo ogni partita controllare se tentativi è minore di record: in questo caso abbiamo battuto il vecchio record: stampare un messaggio di complimenti ed assegnare a record il nuovo valore (che diventa così il nuovo record). Inizializzando record al valore fittizio 1000000000 siamo sicuri che la prima volta che giocherà l'utente batterà sicuramente il record.
Esempio di I/O del programma completo:
Ho pensato un numero da 1 a 20. Prova a indovinarlo!
??? 12
Troppo basso
??? 16
Troppo alto
??? 14
Troppo alto
??? 13
Hai indovinato! Hai impiegato 4 tentativi
Hai battuto il tuo record.
SOLUZIONI

VARIABILI CONTATORE

A volte sappiamo esattamente prima del ciclo quante volte dovremo eseguirlo (ad esempio, se dobbiamo stampare 10 righe di testo, ...). In questi casi si usa in genere un'altra istruzione, il for, ma a scopo didattico useremo una costruzione equivalente che ci renderà poi più facile capire l'altra istruzione.

Una variabile contatore viene inizializzata (in genere a 0) prima del ciclo e viene incrementata ogni volta che il ciclo viene eseguito. La condizione di controllo fa eseguire il ciclo fino a quando la variabile raggiunge il valore voluto.

Vediamo un esempio:

NUOVO PROGRAMMA: tabelline.py

Partiamo con un programma che stampa i numeri da 0 a 9.


i = 0           # inizializza il contatore
while i < 10:
    print(i)
    i += 1      # incrementa il contatore (vuol dire: i = i + 1)

Il while viene ripetuto esattamente 10 volte: i parte da 0 ed ogni volta è incrementata di 1; si uscirà quando i diventerà 10 (cioè i < 10 risulterà falsa). Nell'uso comune, se dobbiamo ripetere un ciclo 100 volte, il contatore andrà da 0 a 99, e quindi la condizione di controllo sarà while i < 100: questa tradizione viene dal linguaggio C.

Modifichiamo temporaneamente il programma così e lanciamolo:


i = 0           
while i < 100:  
    print("AMO GIULIETTA")
    i += 1

Ora ritorniamo al nostro programma e vediamo gli esercizi.

ESERCIZIO 8.5: Modificare il programma in modo che stampi la tabellina del 3. Questo dovrebbe essere l'output:
3 x 1 = 3
3 x 2 = 6
   . . .
3 x 10 = 30
ESERCIZIO 8.6: Modificare il programma in modo che all'inizio chieda all'utente "Quale tabellina vuoi stampare?", accetti in input un numero e stampi quella tabellina.
ESERCIZIO 8.7: Scrivere un programma che stampi una tavola di quadrati e cubi per i numeri da 1 a 100
Esempio di output:
1      1      1
2      4      8
3      9      27
4      16     64
...
SUGGERIMENTO: usa il carattere di tabulazione \t per distanziare i numeri, vedi qui
SOLUZIONI

Fine della lezione