indice: linguaggio_python
Quando si affronta la programmazione si devono indicare al computer delle istruzioni da eseguire. Se il computer potesse comprendere il linguaggio naturale, sarebbe facile chiedere:
Si tratta di istruzioni per noi molto semplici da comprendere, ma che devono essere espresse in modo da poter essere comprese dal computer. Ognuna delle precedenti istruzioni è un esempio di: una condizione, un'iterazione e una sequenza.
Questo teorema afferma che qualsiasi algoritmo può essere descritto utilizzando solo tre tipi di strutture: la sequenziale, la condizionale e l'iterativa.
Gli esempi appena visti erano proprio di queste strutture:
I programmi che seguiranno sono privi di altre funzioni oltre al main() per mettere in evidenza solo queste tre strutture. Al loro fianco sarà presente un diagramma di flusso che usa gli stessi colori per mettere in evidenza le tre strutture.
Le tre strutture possono anche essere combinate insieme tra di loro: si può inserire una struttura sequenziale all'interno di una condizionale(Figura 1), oppure una struttura condizionale dentro una struttura iterativa (Figura 2). In Python l'inserimento di una struttura dentro un'altra si ottiene aumentando l'indentazione, cioè spostando un testo di quattro spazi più a destra, ad esempio:
struttura-esterna struttura-esterna struttura-interna struttura-interna struttura-piu'-interna struttura-esterna struttura-esterna
Poiché queste tre strutture sono indispensabili per descrivere tutti gli algoritmi, ogni linguaggio di programmazione consente di tradurle come istruzioni. Nei prossimi esempi si vedrà che
istruz.1 … istruz.5
if … : … else : …
while … : …
for … in … : …
Un programma può eseguire una lista sequenziale di istruzioni
var. di input | tipo | var. di output | tipo | var. di lavoro | tipo |
---|---|---|---|---|---|
raggio | num. virgola | area | num. virgola | area | num. virgola |
La struttura sequenziale si traduce in Python con una lista ben allineata, perché in Python l'indentazione viene usata proprio per segnare la struttura della sequenza
istruz.1 … istruz.5
raggio = float(raw_input("Inserisci il valore del raggio del cerchio:\n")) area = raggio*raggio*3.14 print "L'area del cerchio vale:", area
Un programma può eseguire istruzioni diverse in base al verificarsi di una condizione
costanti | valore | var. di input | tipo | var. di output | tipo | var. di lavoro | tipo |
---|---|---|---|---|---|---|---|
annoAttuale | 2012 | annoNascita | intero | - | - | - | - |
La struttura condizionale si traduce in Python indicando la condizione dentro il rombo dentro un'istruzione if : che contiene la condizione logica da verificare. Dopo si scrive l'istruzione (o le istruzioni) da eseguire nel caso “vero”. Poi, nell'eventualità che vi siano istruzioni nel caso “falso”, si scrive anche else: e dopo le sue eventuali istruzioni.
if …: … else: …
annoAttuale=2012; annoNascita = int(raw_input("Per favore scrivi l'anno di nascita:\n")) if annoAttuale-annoNascita < 18 : print "Minorenne." else: print "Maggiorenne."
L'algebra di Bool (booleana) è un'algebra nata per definire la logica delle proposizioni, dove si studia lo stato (il valore) di verità delle proposizioni. Una proposizione può essere vera oppure falsa.
ATTENZIONE: non confondere in italiano il termine proposizione con preposizione, che ha un altro significato…
Esempio di proposizione (con valore tra parentesi):
In tale algebra esistono diversi operatori (detti operatori booleani oppure connettivi logici) che possono essere applicati ad una o più proposizioni.
Applicando l'operatore NOT alle due precedenti proposizioni il loro valore di verità diventa l'opposto:
Applicando l'operatore AND, si ottiene una nuova proposizione il cui valore di verità dipende dalla verità di entrambe le proposizioni di partenza (è vera solo se sono entrambe vere)
Applicando l'operatore OR, si ottiene una nuova proposizione il cui valore di verità dipende dalla verità di entrambe le proposizioni di partenza (è vera se almeno una delle due è vera):
Per ogni operatore booleano (AND, OR, NOT, ecc.) si può costruire una tabella che aiuta a descriverlo. Nella seguente tabella sono messe a confronto gli operatori AND e OR. Le prime due colonne sono due proposizioni su cui applicare tali operatori.
P | Q | P AND Q | P OR Q |
---|---|---|---|
V | V | V | V |
V | F | F | V |
F | V | F | V |
F | F | F | F |
La tabella di verità del NOT è più semplice:
P | NOT P |
---|---|
V | F |
F | V |
Di solito gli operatori logici possono essere usati anche dall'elaboratore. Poiché l'elaboratore utilizza il sistema di numerazione in base 2, al valore Vero viene fatto corrispondere il valore 1 mentre al Falso lo 0. Più in generale qualsiasi valore diverso da 0 è considerato vero. In aggiunta a questo tipo di convenzione, il linguaggio C++ permette di usare variabili di un tipo specifico per le espressioni booleane, il tipo bool, e che possono valere: false o true. In quasi tutti i linguaggi di programmazione il numero intero ZERO viene interpretato come False. Qualsiasi altro numero come True. Inoltre ci sono espressioni di confronto come a < b o come x != 0 che hanno un risultato True oppure False, e alle quali possono essere applicati i precedenti operatori logici. Il calcolo automatico di queste espressioni (come a < b) permette al programma di eseguire un'istruzione oppure un'altra a seconda se l'espressione venga valutata vera oppure falsa.
Nel linguaggio Python gli operatori logici AND, OR e NOT vengono tradotti con le seguenti parole chiave:
operatore | simbolo |
---|---|
AND | and |
OR | or |
NOT | not |
Per l'ordine di precedenza vedereoperazioni_su_int
#Domanda: cosa accade se inserisco un valore negativo? umiditaMin=85 umiditaMax=90 umidita = int(raw_input("Scrivi il valore di umidita' relativa, come intero da 0 a 100.\n")) if umidita > umiditaMin and umidita < umiditaMax : # attenzione alla precedenza degli operatori... print "si prevede nebbia" else: print " non si prevede nebbia "
Nella struttura condizionale annidata è consentito l'uso di elif … : (che unisce else con if). La soluzione di questo esercizio viene fornita sia con elif che senza elif.
var. di input | tipo | var. di output | tipo | var. di lavoro | tipo |
---|---|---|---|---|---|
primo | num. intero | - | - | - | - |
secondo | num. intero | - | - | - | - |
terzo | num. intero | - | - | - | - |
- | - | minimo | num. intero | - |
Suggerimento per la traduzione del codice: quando si legge il diagramma di flusso, seguire e tradurre per primo il percorso sempre “vero” e per ultimo il percorso sempre “falso”.
# versione senza elif primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n")) secondo = int(raw_input()) terzo = int(raw_input()) if primo < secondo : if primo < terzo : minimo = primo else: minimo = terzo else: if secondo < terzo : minimo = secondo else: minimo = terzo print minimo
Nella soluzione appena vista è facile capire, per ogni else, a quale if si riferisce, grazie all'indentazione.
# versione con elif primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n")) secondo = int(raw_input()) terzo = int(raw_input()) if primo < secondo : if primo < terzo : minimo = primo else: minimo = terzo elif secondo < terzo : minimo = secondo else: # a quale if fa riferimento questo else? minimo = terzo print minimo
In quest'ultima soluzione non è facile capire a quale if fa riferimento l'ultimo else. Questa è un'ambiguita del linguaggio che si può risolvere stabilendo una regola: ogni else si riferisce all'if più vicino (in questo caso all'elif piu' vicino).
# Questo programma è stato scritto da Fabio # visualizza il minimo di tre numeri # utilizzando gli operatori logici in alternativa alle condizioni annidate primo = int(raw_input("Inserire tre numeri interi separandoli con 'invio' \n")) secondo = int(raw_input()) terzo = int(raw_input()) if primo < secondo and primo < terzo : minimo = primo elif secondo < terzo : minimo = secondo else: minimo = terzo
Esercizi:
La struttura iterativa può essere studiata come composta da diversi elementi (che possono anche coincidere tra loro):
A seconda della posizione occupata dalla condizione di uscita all'interno della ripetizione, la struttura iterativa può essere di due tipi:
In pratica, nel tipo precondizionale, quando la condizione di uscita non è verificata, la ripetizione non viene mai eseguita, mentre nella postcondizionale la ripetizione viene eseguita sempre almeno una volta. In entrambi i casi si esce dal ciclo di ripetizione quando la condizione diventa falsa.
Anche se in teoria esiste, si possono scrivere programmi senza usarla, quindi per ora viene omessa…
Precondizionale significa che la condizione di uscita precede la ripetizione, quindi, in questo caso, potrebbe accadere che, se la condizione non è verificata, la ripetizione non sia mai eseguita
La struttura iterativa precondizionale in Python si può realizzare in due modi: per tradurre un diagramma di flusso si presta molto bene la struttura while, mentre si può usare for nel caso in cui la ripetizione riguardi una sequenza predefinita (come una sequenza di passi numerati o come una lista ordinata di elementi).
# eventuale inizializzazione contatore... while … : …
for i in range(5,1,-1) : print i
5 4 3 2
Il seguente esempio è stato tradotto in due diversi programmi, tra loro equivalenti, per capire come si usa while() e come si usa for(;;). Il programmatore è libero di scegliere le due forme perché sono equivalenti.
var. di input | tipo | var. di output | tipo | var. di lavoro | tipo |
---|---|---|---|---|---|
numero | num. intero | - | - | i | num. intero |
numero = int(raw_input("Inserisci un numero intero da 1 a 10")) i=1; # inizializzazione del contatore while i <= 10 : # condizione di uscita print numero * i, # la virgola in fondo evita di andare a capo i = i + 1 # incremento contatore
numero = int(raw_input("Inserisci un numero intero da 1 a 10")) for i in range(1, 11, 1) # inizializzazione, condizione ed incremento... print numero * i, # la virgola in fondo evita di andare a capo
Anche questo esempio viene risolto sia usando while che for
i = 1 # inizializzazione del contatore totale = 0 # inizializzazione del totalizzatore while i <= 5 : numero = int(raw_input("Inserisci un numero intero")) totale = totale + numero i = i + 1 print totale
totale = 0 # inizializzazione del totalizzatore for i in range(0, 5, 1) : numero = int(raw_input("Inserisci un numero intero")) totale = totale + numero print totale
Scrivere un programma che visualizzi tutte le tabelline pitagoriche dall'uno al dieci.
for i in range(1, 11, 1) : # inizializzazione, condizione ed incremento... for j in range(1, 11, 1) : print j * i, # la virgola in fondo evita di andare a capo print # alcune volte si deve andare a capo
per allineare bene i numeri si deve sostituire la riga “print j * i” con la seguente
print '{0:3d}'.format(j * i)
il codice nelle parentesi graffe ha il seguente significato: (vedere documentazione string)
num1 = int(raw_input("Per favore inserire due numeri interi \n")) num2 = int(raw_input()) if num1 < num2 : for i in range(num1+1,num2,1) : print i, else : print num2
Eseguire la somma di tutti i numeri inseriti fino a che si inserisce 0 per visualizzare il totale. Non si conosce quanti numeri saranno inseriti, meglio usare while…
totale, numero = 0, -1 # inizializzazioni while numero != 0 : numero = int(raw_input("inserire un numero (stop con zero)")) totale = totale + numero print totale }
Prerequisito a questo argomento: le funzioni.
Un programma che ripete più volte la stessa operazione, in teoria, può essere scritto secondo due approcci:
Chi volesse utilizzare l'approccio della iterazione per spiegare come si calcola il fattoriale, potrebbe usare le seguenti parole:
Chi volesse utilizzare l'approccio della ricorsione, invece, potrebbe dire:
Nell'approccio ricorsivo, le parole “e così via” descrivono l'espressione della soluzione in termini di uso quotidiano. Quindi, sebbene, in teoria, ogni problema possa essere risolto usando entrambi gli approcci, vi sono alcuni problemi che si prestano ad essere risolti più facilmente in un modo piuttosto che nell'altro.
Per risolvere un problema con una ricorsione è necessario:
fattoriale(i) = i*fattoriale(i-1); // esprime il problema nei termini di se stesso
fattoriale(0) = 1;
MANCA ESEMPIO FATTORIALE
L'utente inserisce un numero intero compreso tra 1 e 10. L'elaboratore visualizza tutti i numeri compresi tra 1 e 10 ad eccezione di quello inserito dall'utente. Se l'utente inserisce 4, il computer visualizza 1,2,3,5,6,7,8,9,10