Lezione 5 Python Le istruzioni condizionali e la ricorsione

Salve a tutti e bentrovati ad una nuova lezione sul Python! Oggi introdurremo le istruzioni condizionali del Python (molto simili a quelle degli altri linguaggi) e la ricorsione che altro non è che un altro modo di impostare il proprio programma. A breve ne parleremo.

L’operatore modulo

L’operatore modulo opera sugli interi (e sulle espressioni intere) e produce il resto della divisione del primo operando diviso per il secondo. In Python l’operatore modulo è rappresentato dal segno percentuale (%). La sintassi è la stessa degli altri operatori matematici:

[code lang=”objc”]
>>> Quoziente = 7 / 3
>>> print Quoziente
2
>>> Resto = 7 % 3
>>> print Resto
1
[/code]

Così 7 diviso 3 dà 2, con il resto di 1.
L’operatore modulo è molto utile in quanto ti permette di controllare se un

numero è divisibile per un altro: se x % y è 0, allora x è divisibile per y.

Inoltre può essere usato per estrarre la cifra più a destra di un numero:  x%10 restituisce la cifra più a destra in base 10. Allo stesso modo x%100 restituisce le ultime due cifre.

Espressioni Booleane

Un’espressione booleana è un’espressione che può essere o vera o falsa. In Python un’espressione che è vera ha valore 1, un’espressione falsa ha valore 0. E così è anche in molti altri linguaggi di programmazione.

L’operatore == confronta due valori e produce un risultato di tipo booleano:

>>> 3 == 3
1
>>> 3 == 2
0

Nella prima riga i due operandi sono uguali, così l’espressione vale 1 (vero); nella seconda riga 3 e 2 non sono uguali, così otteniamo 0 (falso).

L’operatore == è uno degli operatori di confronto; gli altri sono:

x!=y      #x è diverso da y?
x>y      # x è maggiore di y?
x<y       #x è minore di y?
x>=y      # x `e maggiore o uguale a y?

x<=y      #x è minore o uguale a y?

Sebbene queste operazioni ti possano sembrare familiari, i simboli Python sono diversi da quelli usati comunemente in matematica. Un errore comune è quello di usare il simbolo di uguale (=) invece del doppio uguale (==): ricorda che = è un operatore di assegnazione e == un operatore di confronto. Inoltre in Python non esistono simboli del tipo =< e =>, ma solo gli equivalenti <= e >=.

Operatori logici

Ci sono tre operatori logici: and, or e not. Il significato di questi operatori è simile al loro significato in italiano: per esempio, (x>0) and (x<10) è vera solo se x è più grande di 0 e meno di 10.

(n%2==0) or (n%3==0) è vera se si verifica almeno una delle due condizioni e ciò è se il numero è divisibile per 2 o per 3.

Infine, l’operatore not nega il valore di un’espressione booleana, trasformando in falsa un’espressione vera e viceversa. Cos`ı se x>y è vera (x è maggiore di y), not(x>y) è falsa.

A dire il vero gli operatori booleani dovrebbero restituire un valore vero o falso, ma da questo punto di vista Python non sembra essere troppo fiscale: infatti ogni valore diverso da zero viene considerato vero e lo zero è considerato falso.

>>> x=5 >>> xand1 1
>>> y=0 >>> yand1 0

In generale, le righe appena viste pur essendo lecite non sono considerate un buon esempio di programmazione: se vuoi confrontare un valore con zero è sempre meglio farlo in modo esplicito, con un’espressione del tipo

>>> x!=0

Esecuzione condizionale

Per poter scrivere programmi di una certa utilità dobbiamo essere messi in grado di valutare delle condizioni e di far seguire differenti percorsi al flusso di esecuzione a seconda del risultato della valutazione. Le istruzioni condizionali ci offrono questa possibilità. La forma più semplice di istruzione if è la seguente:

if x > 0:
  print "x e’ positivo"

L’espressione booleana dopo l’istruzione if è chiamata condizione. L’istruzione indentata che segue i due punti della riga if viene eseguita solo se la condizione è vera. Se la condizione è falsa non viene eseguito alcunchè.

Come nel caso di altre istruzioni composte, l’istruzione if è costituita da un’intestazione e da un blocco di istruzioni:

INTESTAZIONE:
  PRIMA RIGA DI ISTRUZIONI
  SECONDA RIGA DI ISTRUZIONI
  ......
  ULTIMA RIGA DI ISTRUZIONI

L’intestazione inizia su di una nuova riga e termina con il segno di due punti. La serie di istruzioni indentate che seguono sono chiamate blocco di istruzioni. La prima riga di istruzioni non indentata marca la fine del blocco di istruzioni e non ne fa parte. Un blocco di istruzioni all’interno di un’istruzione composta è anche chiamato corpo dell’istruzione.

Non c’è un limite al numero di istruzioni che possono comparire nel corpo di un’istruzione if ma deve sempre essercene almeno una. In qualche occasione può essere utile avere un corpo vuoto, ad esempio quando il codice corrispondente non è ancora stato scritto ma si desidera ugualmente poter provare il programma. In questo caso puoi usare l’istruzione pass, che è solo un segnaposto e non fa niente. Se non vi è chiaro potete considerare (se conoscete l’assembly) l’istruzione pass come l’istruzione NOP, No Operation, ovvero: non fare nulla e prosegui.

if x > 0: pass

Esecuzione alternativa

Una seconda forma di istruzione if è l’esecuzione alternativa, nella quale ci sono due possibilità di azione e il valore della condizione determina quale delle due debba essere scelta. La sintassi è:

[code lang=”objc”]
if x%2 == 0:
print x, &quot;e’ pari&quot;
else:
print x, &quot;e’ dispari&quot;
[/code]

Se il resto della divisione intera di x per 2 è zero allora sappiamo che x è pari e il programma mostra il messaggio corrispondente. Se la condizione è falsa viene eseguita la serie di istruzioni descritta dopo la riga else (che in inglese significa “altrimenti”).

Le due alternative sono chiamate ramificazioni perch ́e rappresentano delle ramificazioni nel flusso di esecuzione del programma, e solo una di esse verrà effettivamente eseguita.

Una nota: se avete bisogno di controllare la parità di un numero (vedere se il numero è pari o dispari), potreste desiderare di creare una funzione apposita da poter riutilizzare in seguito:

[code lang=”objc”]
def Parita(x):
if x%2 == 0:
print x, &quot;e’ pari&quot;
else:
print x, &quot;e’ dispari&quot;
[/code]

Così per ogni valore intero di x, Parita mostra il messaggio appropriato. Quando chiamate questa funzione puoi fornire qualsiasi espressione intera come argomento.

>>> Parita(17)
>>> Parita(y+1)

Condizioni in serie

Talvolta ci sono più di due possibilità per la continuazione del programma, così possiamo aver bisogno di più di due ramificazioni. Un modo per esprimere questo caso sono le condizioni in serie:

[code lang=”objc”]
if x &lt; y:
print x, &quot;e’ minore di&quot;, y
elif x &gt; y:
print x, &quot;e’ maggiore di&quot;, y
else:
print x, &quot;e&quot;, y, &quot;sono uguali&quot;
[/code]

elif è l’abbreviazione di “else if”, che in inglese significa “altrimenti se”. Anche in questo caso solo uno dei rami verrà eseguito, a seconda del confronto tra x e y. Non c’à alcun limite al numero di istruzioni elif ma è eventualmente possibile inserire un’unica istruzione else che deve essere l’ultima dell’elenco e che rappresenta l’azione da eseguire quando nessuna delle condizioni precedenti è stata soddisfatta. La presenza di un’istruzione else è facoltativa.

[code lang=”objc”]
if scelta == ’A’:
FunzioneA()
elif scelta == ’B’:
FunzioneB()
elif scelta == ’C’:
FunzioneC()
else:
print &quot;Scelta non valida&quot;
[/code]

Le condizioni sono controllate nell’ordine in cui sono state scritte. Se la prima è falsa viene provata la seconda e così via. Non appena una è verificata viene eseguito il ramo corrispondente e l’intera istruzione if viene conclusa. In ogni caso, anche se fossero vere altre condizioni, dopo l’esecuzione della prima queste vengono trascurate. Se nessuna condizione è vera ed è presente un else verrà eseguito il codice corrispondente; se non  è presente non verrà eseguito niente.

Condizioni annidate

Un’espressione condizionale può anche essere inserita nel corpo di un’altra espressione condizionale: un’espressione di questo tipo viene detta “condizione annidata”.

[code lang=”objc”]
if x == y:
print x, &quot;e&quot;, y, &quot;sono uguali&quot;&lt;/pre&gt;
else:
if x &lt; y:
&lt;pre&gt; print x, &quot;e’ minore di&quot;, y
else:
print x, &quot;e’ maggiore di&quot;, y
[/code]

La prima condizione (if x == y) contiene due rami: il primo è scelto quando x e y sono uguali, il secondo quando sono diversi. All’interno del secondo (subito sotto il primo else:) troviamo un’altra istruzione if, che a sua volta prevede un’ulteriore ramificazione. Entrambi i rami del secondo if sono istruzioni di stampa ma potrebbero contenere a loro volta ulteriori istruzioni condizionali.

Sebbene l’indentazione delle istruzioni renda evidente la struttura dell’esempio, le istruzioni condizionali annidate in livelli sempre più profondi diventano sempre più difficili da leggere, quindi è una buona idea evitarle quando è possibile.

Gli operatori logici permettono un modo molto semplice di semplificare le espressioni condizionali annidate:

[code lang=”objc”]
if 0 &lt; x:
if x &lt; 10:
print &quot;x e’ un numero positivo.&quot;
[/code]

L’istruzione di stampa print è eseguita solo se entrambe le condizioni (x>0 e x<10) sono verificate contemporaneamente. Possiamo quindi usare l’operatore booleano and per combinarle:

[code lang=”objc”]
if 0&lt;x and x&lt;10:
print &quot;x e’ un numero positivo.&quot;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;

Questo tipo di condizione è così frequente che Python permette di usare una forma semplificata che ricorda da vicino quella corrispondente usata in matematica:
&lt;pre&gt;if 0 &lt; x &lt; 10:
print &quot;x e’ un numero positivo.&quot;
[/code]

A tutti gli effetti i tre esempi sono equivalenti per quanto riguarda la semantica del programma.

L’istruzione return

L’istruzione return ti permette di terminare l’esecuzione di una funzione prima di raggiungerne la fine. Questo può servire quando viene riconosciuta una condizione d’errore:

import math

[code lang=”objc”]
def StampaLogaritmo(x):
if x &lt;= 0:
print &quot;Inserire solo numeri positivi!&quot;
return
risultato = math.log(x)
print &quot;Il logaritmo di&quot;,x,&quot;e’&quot;, risultato
[/code]

La funzione StampaLogaritmo accetta un parametro chiamato x. La prima operazione controlla che esso sia positivo; in caso contrario stampa un messaggio d’errore e termina prematuramente la funzione con return.

Ricordate che dovendo usare una funzione del modulo math è necessario importare il modulo!

Ricorsione

Abbiamo detto che è perfettamente lecito che una funzione ne chiami un’altra e di questo avete avuto modo di vedere parecchi esempi. Abbiamo invece trascurato di dirti che è anche lecito che una funzione possa chiamare sé stessa. Può non essere immediatamente ovvio il motivo per cui questo sia utile, ma questa è una delle cose più interessanti che un programma possa fare. Per fare un esempio dai un’occhiata a questa funzione:

[code lang=”objc”]
def ContoAllaRovescia(n):
if n == 0:
print &quot;Partenza!&quot;
else:
print n
ContoAllaRovescia(n-1)
[/code]

ContoAllaRovescia si aspetta che il parametro sia un intero positivo. Se n vale 0, viene stampata la scritta Partenza!. Altrimenti stampa n e poi chiama la funzione ContoAllaRovescia (cioè sé stessa) con un argomento che vale n-1.Cosa succede quando chiamiamo una funzione come questa?

>>> ContoAllaRovescia(3)
L’esecuzione di ContoAllaRovescia inizia con n=3. Dato che n non è 0, essa

stampa il valore 3, e poi richiama sé stessa…

L’esecuzione di ContoAllaRovescia inizia con n=2. Dato che n non è 0, essa stampa il valore 2, poi richiama sé stessa…

L’esecuzione di ContoAllaRovescia inizia con n=1. Dato che n non è 0, essa stampa il valore 1, poi richiama sé stessa…

L’esecuzione di ContoAllaRovescia inizia con il valore di n=0. Dal momento che n è 0, essa stampa il testo “Partenza!” e poi ritorna.

La funzione ContoAllaRovescia che aveva n=1; e poi ritorna.

La funzione ContoAllaRovescia che aveva n=2; e poi ritorna. E quindi torna in page61image10400 __main__   (questo è un trucco). Il risultato è questo:

3
2
1
Partenza!

Ricorsione infinita

Se una ricorsione non raggiunge mai il suo stato di base la chiamata alla funzione viene eseguita all’infinito ed in teoria il programma non giunge mai alla fine. Questa situazione è conosciuta come ricorsione infinita e non è generalmente considerata una buona cosa. Questo è un programma minimo che genera una ricorsione infinita:

def Ricorsione():
  Ricorsione()

Nella maggior parte degli ambienti un programma con una ricorsione infinita non viene eseguito senza fine, dato che ogni chiamata ad una funzione impegna un po’ di memoria del computer e questa memoria prima o poi finisce. Python stampa un messaggio d’errore quando è stato raggiunto il massimo livello di ricorsione possibile:

  File "<stdin>", line 2, in Ricorsione
  ...
  File "<stdin>", line 2, in Ricorsione
RuntimeError: Maximum recursion depth exceeded

Inserimento da tastiera

I programmi che abbiamo scritto finora sono piuttosto banali, nel senso che non accettano inserimenti di dati da parte dell’operatore, limitandosi a eseguire sempre le stesse operazioni.

Python fornisce un insieme di funzioni predefinite che permettono di inserire dati da tastiera. La più semplice di esse è raw input. Quando questa funzione è chiamata il programma si ferma ed attende che l’operatore inserisca qualcosa, confermando poi l’inserimento con Invio (o Enter). A quel punto il programma riprende e raw input ritorna ciò che l’operatore ha inserito sotto forma di stringa:

>>> Inserimento = raw_input ()
Testo inserito
>>> print Inserimento
Testo inserito

Prima di chiamare raw input è una buona idea stampare un messaggio che avvisa l’operatore di ciò che deve essere inserito. Questo messaggio è chiamato prompt. L’operazione è così comune che il messaggio di prompt può essere passato come argomento a raw input:

>>> Nome = raw_input ("Qual e’ il tuo nome? ")
Qual e’ il tuo nome? Arturo
>>> print Nome
Arturo

Se il valore da inserire è un intero possiamo usare la funzione input:

Prompt = "A che velocita’viaggia il treno?\n"
Velocita = input(Prompt)

Se l’operatore inserisce una serie di cifre questa è convertita in un intero ed assegnata a Velocita. Sfortunatamente se i caratteri inseriti dall’operatore non rappresentano un numero, il programma stampa un messaggio d’errore e si blocca:

>>> Velocita = input (Prompt)
A che velocita’viaggia il treno?
ottanta all’ora
SyntaxError: invalid syntax

Per evitare questo tipo di errori è generalmente meglio usare la funzione raw_input per ottenere una stringa di caratteri e poi usare le funzioni di conversione per ottenere gli altri tipi.

E anche per oggi è tutto ragazzi, vi aspetto alla prossima!