Nota: Lavori in corso.
Questa è una breve introduzione all'arte della programmazione, con esempi scritti nel linguaggio di programmazione Python. (Se sai già programmare, ma vuoi una breve introduzione a Python, controlla l'articolo Python Istantaneo.)
(Lodi per l'articolo. Pagina Python di M. L. Hetland)
1. L'ambiente
Per programmare in Python, devi avere
istallato l'interprete. Esiste per quasi tutte le piattaforme
(compresi Macintosh, Linux e Windows). Altre informazioni su questo
sono al sito web di Python. Serve anche
un programma editore di testi
(come emacs, notepad o altri simili).
2. Cos'è la programmazione?
Programmare un computer significa dargli un insieme di istruzioni
che gli dicono cosa fare. Un programma per computer assomiglia in
molti modi a una ricetta, come quelle che usiamo in cucina. Per
esempio [1]:
Insalata Fiesta allo Spam [spalla cotta] Ingredienti: Condimento: 1/4 tazza di succo di limone 1/4 tazza di salsa di soia 1/4 tazza di acqua 1 cucchiaio di olio di semi 3/4 di cucchiaino di cumino 1/2 di cucchiaino di origano 1/4 cucchiaino di tabasco piccante 2 teste d'aglio tritate Salad: 1 lattina (3 etti) di carne in scatola Spam tagliata a strisce 1 cipolla affettata 1 peperone verde tagliato a strisce Lattuga 12 pomodorini tagliati a metà Istruzioni: In una giara a chiusura ermetica, combinare tutti gli ingredienti del condimento; scuotere bene. Mettere le strisce di Spam in un saacchetto di plastica. Versare il condimento sulla Spam. Sigillare il sacchetto; marinare per 30 minuti in frigorifero. Togliere la Spam dal sacchetto; mettere a parte 2 cucchiai del condimento, scaldandoli in una padella grande. Aggiungere la Spam, la cipolla, e il peperone verde. Cuocere 3-4 minuti, sinchè la Spam si scalda. Guarnire 4 piatti con la lattuga. Versare col cucchiaio la miscela calda sulla lattuga. Guarnire con i mezzi pomodorini. Sono 4 porzioni.
Naturalmente, nessun computer capirebbe questo... e la maggior parte dei computer non potrebbero fare un'insalata anche se capissero la ricetta. Quindi cosa dobbiamo fare per rendere questo più amichevole per computer? Beh -- sostanzialmente due cose. Dobbiamo (1) parlare in un modo che il computer possa capire, e (2) parlare di cose sulle quali esso può fare qualcosa.
Il primo punto significa che dobbiamo usare un linguaggio -- un linguaggio di programmazione per cui abbiamo un programma interprete, e il secondo punto significa che non possiamo aspettarci che il computer faccia un'insalata -- ma possiamo aspettarci che sommi numeri, scriva cose su schermo ecc.
3. Ciao...
C'è una tradizione nei corsi di programmazione
di cominciare sempre con un programma che stampa "Ciao, mondo!" sullo
schemo. In Python, questo è semplicissimo:
print "Ciao, mondo!"
Questo è sostanzialmente come la ricetta di prima (anche se è molto più corto!). Dice al computer cosa fare: stampare "Ciao, mondo!". Facilissimo. E se volessimo che facesse più cose?
print "Ciao, mondo!" print "Addio, mondo!"
Non molto più difficile, vero? E non molto interessante... vogliamo
poter fare qualcosa con gli ingredienti, come nella
insalata di spam. Beh -- che ingredienti abbiamo? Anzitutto, abbiamo
stringhe di testo, come "Ciao, mondo!"
, ma abbiamo
anche numeri.
Supponiamo di volere che il computer calcoli per noi l'area di
un rettangolo. Potremmo dargli la seguente
ricettina:
# Area di un Rettangolo # Ingredienti: larghezza = 20 altezza = 30 # Istruzioni: area = larghezza*altezza print area
Vedi probabilmente la somiglianza (leggera) con la ricetta
dell'insalata di spam. Ma come funziona? Anzitutto, le righe che
iniziano con #
si chiamano commenti e vengono
in effetti ignorate dal computer. Tuttavia, inserire piccole
spiegazioni come queste può essere importante per rendere i
tuoi programmi più leggibili per gli umani.
Le righe che assomigliano a foo = bar
si chiamano
assegnamenti. Nel caso di larghezza = 20
dichiamo al
computer che la larghezza è 20 da questo punto in avanti. Cosa significa
che "la larghezza è 20"? Significa che una variabile di nome
"larghezza" viene creata (o se esiste già, viene riusata) e riceve il
valore 20. Così, quando usiamo la variabile più avanti, il computer
conosce il suo valore. Dunque,
larghezza*altezza
è sostanzialmente lo stesso che
20*30
espressione che viene calcolata, dando 600, valore che è poi assegnato alla variabile col nome "area". L'ultima istruzione del programma stampa il valore della variabile "area", quindi quello che vedi eseguendo questo programma è semplicemente
600
Nota: In alcuni linguaggi devi dire al computer sin dall'inizio del programma di quali variabili avrai bisogno (come gli ingredienti dell'insalata) - Python, invece, è così furbo da scoprire questo man mano che procede.
4. Feedback
OK. Ora puoi eseguire calcoli semplici, o
anche piuttosto avanzati. Per esempio, potresti fare un programma
per calcolare l'area di un cerchio invece che di un
rettangolo:
raggio = 30 print raggio*raggio*3.14
Ma questo non è davvero più interessante del programma del rettangolo. Almeno non nella mia opinione. È abbastanza poco flessibile. E se il cerchio che ci interessa avesse un raggio di 31? Come farebbe il computer a saperlo? È un po' come la parte della ricetta dell'insalata che dice "Cuocere 3-4 minuti, sinchè la Spam si scalda". Per sapere quando è cotta, dobbiamo controllare. Ci serve feedback, ovvero input. Come fa il computer a sapere il raggio del nostro cerchio? Anche a lui serve input... quel che possiamo fare è dirgli di chiedere il raggio:
raggio = input("Quant'è il raggio?") print raggio*raggio*3.14
Così le cose cominciano a farsi
belle... input
è una cosa chiamata
funzione. (Imparerai presto a crearti le tue.
input
è una funzione pre-costruita [built-in] del linguaggio
Python). Scrivere soltanto
input
non farebbe molto... devi mettere un paio di parentesi alla fine. Quindi
input()
funzionerebbe - aspetterebbe soltanto che l'utente
immetta il raggio. La versione di prima è forse più amichevole, però,
visto che prima stampa una domanda. Quando mettiamo qualcosa come la
stringa di domanda "Quant'è il raggio?" fra le parentesi di una chiamata
a funzione, questo si chiama passare un parametro alla
funzione. La cosa (o le cose) fra le parentesi è (o sono) il (i)
parametro(i). In questo caso passiamo come parametro una
domanda così che
input
sappia cosa emettere prima di ottenere la
risposta dall'utente.
Ma come fa la risposta ad arrivare alla variabile
raggio
? La funzione
input
, quando è chiamata,
restituisce un valore (come molte altre
funzioni). Non sei obbligato a usare questo valore, ma, nel nostro
caso, è quel che vogliamo. Quindi, le due istruzioni seguenti hanno
significati molto
differenti:
foo = input bar = input()
foo
ora contiene la stessa funzione di input
(così che può in effetti essere usata come
foo("Quanti anni hai?")
) (questo si chiama
chiamata a funzione dinamica) mentre bar
contiene
qualsiasi cosa l'utente abbia immesso.
5. Flusso
Ora possiamo scrivere programmi che eseguono
semplici azioni (aritmetica e stampa) e possono ricevere input
dall'utente. Questo è utile, ma siamo ancora limitati alla
cosiddetta esecuzione sequenziale dei comandi, cioè
devono essere eseguiti in ordine fisso. La maggior parte della
ricetta dell'insalata di spam è sequenziale o lineare in questo
senso. Ma se volessimo dire al computer come controllare la
cottura della spam? Se è calda, va rimossa dal forno -- se no,
va cotta per un altro minuto circa. Come esprimere questo?
Quel che vogliamo fare è controllare il flusso del programma. Può andare in due direzioni -- togliere la spam, o lasciarla nel forno. Possiamo scegliere, e la condizione è se sia o meno già calda. Questa si chiama esecuzione condizionale. Possiamo fare così:
temperatura = input("Qual è la temperatura della spam?") if temperatura > 50: print "L'insalata è cotta a puntino." else: print "Cuoci ancora un poco l'insalata."
Il significato di questo dovrebbe essere ovvio: se la temperatura è maggiore di 50 (gradi centigradi), stampa un messaggio che dice all'utente che è cotta, altrimenti, dì all'utente di cuocere l'insalata ancora un poco.
Nota: Il rientro ("indent") è importante in Python. I blocchi di esecuzione condizionale (e i cicli e le definizioni di funzione - vedi oltre) devono essere rientrati (e ogni loro riga dev'essere rientrata dello stesso numero di spazi) così che l'interprete sappia dove cominciano e finiscono. Ciò rende anche il programma più leggibile per gli umani.
Torniamo ai nostri calcoli d'area. Vedi cosa fa questo programma?
# Programma calcolo aree print "Benvenuti al Programma calcolo aree" print "---------------------------------------" print # Stampa il menu: print "Scegliere una forma:" print "1 Rettangolo" print "2 Cerchio" # La scelta dell'utente: forma = input("> ") # Calcola l'area: if forma == 1: altezza = input("Immettere l'altezza: ") larghezza = input("Immettere la larghezza: ") area = altezza*larghezza print "L'area è", area else: raggio = input("Immettere il raggio: ") area = 3.14*(raggio**2) print "L'area è", area
Cose nuove in questo esempio:
print
usato da solo emette una riga vuota
==
controlla se due cose sono eguali, ben diverso da
=
, che assegna il valore sul lato destro alla variabile sulla
sinistra. Questa è una distinzione importante!
**
è l'operatore di elevazione a potenza in
Python - così,
il raggio al quadrato si scrive raggio**2
.
print
può emettere più di una cosa, basta separarle con
virgole. (Nell'output saranno separate da semplici spazi).Il programma è molto semplice: chiede un numero, che gli dice se
l'utente voglia calcolare l'area di un rettangolo o di un cerchio. Poi,
usa una istruzione di
if
(esecuzione condizionale) per decidere quale blocco debba
usare per il calcolo dell'area. Questi due blocchi sono essenzialmente
gli stessi usati nei precedenti esempi sull'area. Nota come i commenti
rendano il codice più leggibile. È stato detto che il primo
comandamento della programmazione è "Commentare!". Se non altro,
è una buona abitudine da prendere.
Esercizio:
Estendere questo programma aggiungendo il calcolo
dell'area di un quadrato, dove basta che l'utente immetta la lunghezza di un
lato. Per fare questo ti serve sapere una cosa: se hai più di due
scelte, puoi scrivere qualcosa
come:
if foo == 1: # Fai qualcosa... elif foo == 2: # Fai qualcosa d'altro... elif foo == 3: # Fai qualcosa di differente... else: # Se tutto il resto fallisce...
Qui elif
è un codice misterioso che significa "else if"
:)
. Quindi: se foo
è 1, fai qualcosa; se no, se
foo
è 2, fai qualcos'altro, ecc. Potresti voler aggiungere
anche altre opzioni al programma, tipo i triangoli o anche poligoni
arbitrari. Decidi tu.
6. Cicli
L'esecuzione sequenziale e i condizionali sono solo
due dei tre mattoni fondamentali della programmazione.
Il terzo è il ciclo. Nella sezione precedente ho proposto una
soluzione per controllare se la spam fosse calda, ma era chiaramente
inadeguata. E se la spam non fosse a puntino neppure la prossima
volta che la controlliamo? Come potremmo sapere quante volte dobbiamo
controllarla? La verità è che non possiamo. E non dovremmo. Dovremmo
poter chiedere al computer di continuare a controllare sinchè non ha
finito. Come facciamo? Hai indovinato - usiamo un ciclo, ovvero
esecuzione ripetuta.
Python ha due tipi di ciclo: cicli while e cicli for. I cicli for sono forse i più semplici. Per esempio:
for cibo in "spam", "uova", "pomodori": print "Io mangio", food
Questo significa: per ciascun elemento della lista "spam", "uova",
"pomodori"
, stampalo. Il blocco entro il ciclo ("corpo" del
ciclo) è eseguito una volta
per ciascun elemento, e ogni volta l'elemento corrente è assegnato alla
variabile
cibo
(in questo caso). Un altro esempio:
for numero in range(1,100): print "Ciao, mondo!" print "Solo", 100-number, "altre volte..." print "Ciao, mondo!" print "Questa era l'ultima... puff!"
La funzione range
restituisce la lista dei numeri nella
gamma passatale (compreso il primo, escluso l'ultimo... in questo caso,
[1..99]). Quindi, per parafrasare:
Il contenuto del ciclo è eseguito per ogni numero nella gamma dei numeri da (compreso) 1 sino a (escluso) 100. (Quel che poi fanno il corpo del ciclo e le istruzioni successive lo lasciamo come esercizio).
Ma questo non ci aiuta davvero col nostro problema di cucina. Se
volessimo controllare lo spam cento volte, sarebbe una soluzione
assai graziosa; ma non sappiamo se basta - o se sia troppo. Vogliamo
solo continuare a controllare sinchè non è abbastanza caldo
(o, sino a che è abbastanza caldo - questione di punti di
vista). Quindi,
usiamo while
:
# Programma di cottura spam # Recupera la funzione sleep from time import sleep print "Comincia a cuocere la spam. (Torno fra 3 minuti)" # Aspetta 3 minuti (cioè, 3*60 secondi)... sleep(180) print "Sono tornato :)" # Quanto caldo è sufficiente? caldo_a_sufficienza = 50 temperatura = input("Quanto è calda la spam? ") while temperatura < caldo_a_sufficienza: print "Non è abbastanza calda... cuocila ancora un po'..." sleep(30) temperatura = input("OK. Adesso quanto è calda? ") print "È calda a sufficienza - toglila!"
Cose nuove in questo esempio...
sleep
(che fa "dormire" il programma
per un certo numero di secondi) dal modulo time
che è fra quelli acclusi a Python. (Puoi anche farti i tuoi moduli...)
Esercizio 1
Scrivi un programma che legge continuamente
numeri scritti dall'utente e li somma sinchè la somma raggiunge 100.
Scrivi un altro programma che legge 100 numeri dall'utente e stampa
la loro somma.
7. Programmi più grandi - l'astrazione
Se vuoi un sommario
dei contenuti di un libro, non leggi tutte le pagine - dai un'occhiata
all'indice, giusto? Esso elenca semplicemente gli argomenti principali
del libro. Ora - immagina di scrivere un libro di cucina. Molte delle
ricette, come "Spam cremoso e maccheroni" o "Torta svizzera di spam"
possono contenere cose simili, come spam, in questo caso -- però non
vorresti ripetere come fare lo spam in ogni ricetta (vabbè -- non è
proprio che si faccia lo spam... ma abbi pazienza per
amor dell'esempio
:)
).
Metteresti la ricetta dello spam in un capitolo separato, facendovi
semplicemente riferimento nelle altre ricette. Così - invece di
scrivere l'intera ricetta ogni volta, ti basterebbe usare un
rimando ad un capitolo. Nella programmazione dei computer, questa
si chiama astrazione.
Abbiamo già incontrato qualcosa del genere? Sì. Invece di dire
al computer esattamente come ottenere una risposta dall'utente (OK, non
avremmo davvero potuto farlo... ma non potremmo neppure fare davvero
la spam, quindi...
:)
) usavamo semplicemente
input
- una funzione. Possiamo farci le nostre funzioni,
per usarle per questo tipo di astrazione.
Diciamo che vogliamo trovare il più grande intero che sia meno
di un certo numero positivo. Per esempio, dato il numero 2.7, questo
sarebbe 2. Questo si chiama spesso il "floor" del dato numero. (Questo
si potrebbe fare con la funzione built-in del Python
int
, ma, ancora, abbiate pazienza...) Come faremmo? Una
semplice soluzione sarebbe provare tutte le possibilità da zero:
numero = input("Quant'è il numero? ") floor = 0 while floor < numero: floor = floor+1 floor = floor-1 print "Il floor di", numero, "è", floor
Nota che il ciclo termina quando
floor
non è più minore del numero; aggiungiamo
uno ad esso una volta di troppo. Quindi dobbiamo poi sottrarre
uno. E se volessimo usare questo 'floor' in una complessa espressione
matematica? Dovremmo scrivere l'intero ciclo per ogni numero di cui ci
serve il floor. Non molto simpatico... probabilmente hai indovinato
cosa faremo invece: metteremo tutto in una nostra funzione,
chiamata
"floor":
def floor(numero): risultato = 0 while risultato < numero: risultato = risultato+1 risultato = risultato-1 return risultato
Cose nuove in questo esempio...
def
, seguita dal
nome e dai parametri previsti fra parentesi.
return
(che inoltre termina automaticamente la funzione). Ora che l'abbiamo definita, possiamo usarla così:
x = 2.7 y = floor(2.7)
A questo punto, y
dovrebbe valere 2. Si possono fare anche
funzioni con più di un parametro:
def somma(x,y): return x+y
Esercizio 2
Scrivi una funzione che implementa il metodo
di Euclide per trovare il massimo fattor comune fra due numeri. Funziona
così:
Suggerimenti:
x
per z
si calcola con l'espressione x % z
x, y = y,
y+1
. Qui x
riceve il valore di y
(cioè, il
valore che y
aveva prima dell'assegnazione) e y
è
incrementata di uno8. Ancora sulle funzioni
Com'è andato l'esercizio? È stato difficile?
Ancora un po' confuso sulle funzioni? Non preoccuparti - non ho ancora
terminato di trattare l'argomento.
Il tipo di astrazione che abbiamo usato costruendo funzioni è spesso chiamata astrazione procedurale, e molti linguaggi usano la parola procedura oltre alla parola funzione. I due concetti sono differenti, ma entrambi sono chiamati funzioni in Python (visto che sono definiti e usati allo stesso modo, più o meno).
Qual è la differenza (in altri linguaggi) fra funzioni e procedure? Beh - come hai visto nella sezione precedente, le funzioni possono restituire un valore. La differenza è che le procedure non restituiscono un tale valore. In molti modi, questa idea di dividere le funzioni in due tipi - quelle che in effetti restituiscono un valore, e quelle che non lo restituiscono - può essere assai utile.
Una funzione che non restituisce un valore (una "procedura") è usata come "sotto-programma" ovvero "subroutine". Chiamiamo la funzione, e il programma fa qualcosa, tipo fare la panna montata o che altro. Possiamo usare questa funzione in molti posti senza riscrivere il codice. (Questo è chiamato riuso del codice - ne riparleremo più avanti).
L'utilità di una simile funzione è nei suoi effetti collaterali - essa cambia il proprio ambiente (ad esempio, mescolando lo zucchero alla panna e montandola...). Vediamo un esempio:
def ciao(chi):
print "Ciao,", chi
ciao("mondo")
# Stampa "Ciao, mondo"
Stampare roba è considerato un effetto collaterale, e poichè questo è tutto che fa quella funzione, è proprio tipico per una cosiddetta procedura. Ma... non cambia davvero il proprio ambiente, no? Come potrebbe farlo? Proviamo:
# Il modo *sbagliato* di farlo eta = 0 def cambiaEta(a): eta = a cambiaEta(100) print eta # Stampa "0"
Cosa c'è di sbagliato qui? Il problema è che la funzione
cambiaEta
crea la propria variabile locale,
che si chiama egualmente eta
, ma è vista solo entro
cambiaEta
. Come possiamo evitarlo? Possiamo usare una
cosa chiamata variabili globali.
Nota: le variabili globali non sono molto usate in Python. Esse possono facilmente portare a difetti di struttura, o a quel che si chiama codice-spaghetti. Le uso qui per portare a tecniche più complesse; tu, se appena puoi, evitale.
Dicendo all'interprete che una variabile è globale (con una
istruzione come global eta
) gli indichiamo in
pratica di usare la variabile che è fuori dalla funzione
invece di crearne una nuova locale (quindi, è
global in contrapposizione a local.)
Il programma può dunque essere riscritto così:
# Modo corretto, ma non molto buono, di farlo eta = 0 def cambiaEta(a): global eta eta = a cambiaEta(100) print eta # Stampa "100"
Quando imparerai gli oggetti (più avanti), vedrai che un
modo più appropriato di fare questo è usare un oggetto con
una proprietà eta
e un metodo cambiaEta
.
Nella sezione sulle strutture dati, vedrai qualche esempio
migliore di funzioni che cambiano il proprio ambiente.
Beh - e le vere funzioni, allora? Cos'è una funzione, in realtà? Le funzioni matematiche sono una specie di "macchina" che riceve dell'input e calcola un risultato. Torna lo stesso risultato ogni volta, se le si presenta lo stesso input. Per esempio:
def quadrato(x): return x*x
Questo equivale alla funzione matematica f(x)=x2. Si comporta da brava funzione, cioè si appoggia solo sul suo input, e non cambia il proprio ambiente in alcun modo.
Quindi - ho mostrato due modi di fare funzioni: un modo è
come una procedura, e non restituisce un risultato; l'altro è
più come una funzione matematica e non fa altro che
restituire un risultato (o quasi). Naturalmente, è possibile fare
qualcosa di intermedio fra questi due estremi, benchè, se una
funzione cambia cose, dovrebbe essere reso chiaro che lo fa.
Potresti segnalare questo col suo nome, per esempio usando solo
un sostantivo per denominare funzioni "pure" come
quadrato
e un imperativo per funzioni simili a
procedure, come cambiaEta
.
9. Più ingredienti - strutture dati
Beh - sai già molto:
come ottenere input e dare output, come strutturare algoritmi
(programmi) complicati, come eseguire aritmetica; eppure il
meglio deve ancora venire.
Che ingredienti abbiamo usato nei nostri programmi sinora? Numeri e stringhe. Giusto? Un po' noioso... ora introduciamo un altro paio di ingredienti per rendere le cose un poco più eccitanti.
Le strutture dati sono ingredienti che strutturano i dati (sorpresa, sorpresa...). Un singolo numero non ha molta struttura, no? Ma diciamo che vogliamo più numeri messi assieme come singolo ingrediente - questo avrebbe un po' di struttura. Per esempio, potremmo volere una lista di numeri. Questo è facile:
[3,6,78,93]
Ho nominato le liste nella sezione sui cicli, ma non ne ho davvero detto molto. Beh - questo è come si fanno. Basta elencare gli elementi, separati da virgole e chiusi fra parentesi quadre.
Saltiamo dritti in un esempio che calcola i numeri primi (cioè divisibili solo per se stessi e 1):
# Calcola tutti i primi sotto 1000 # (non il miglior modo di farlo, ma...) risultati = [1] candidati = range(3,1000) base = 2 prodotto = base while candidati: while prodotto < 1000: if prodotto in candidati: candidati.remove(prodotto) prodotto = prodotto+base risultati.append(base) base = candidati[0] prodotto = base del candidati[0] print risultati
Cose nuove in questo esempio...
range
restituisce in realtà una lista
che può essere usata come qualsiasi altra lista. (Comprende il primo
indice, ma non l'ultimo).
while candidati
significa
"finchè la lista chiamata candidati non è vuota" cioè più
semplicemente "finchè ci sono ancora candidati".
if unElemento in unaLista
per controllare
se un elemento è in una lista.
unaLista.remove(unElemento)
per togliere
unElemento
da unaLista
.
unaLista.append(unAltraLista)
. Puoi usare anche
+
(ad esempio unaLista = unaLista+unAltraLista
) ma
non è altrettanto efficiente.
0
) fra parentesi quadre dopo il nome della lista.
Così ad esempio unaLista[3]
è il quarto elemento
della lista unaLista
. (Ci torneremo più avanti)
del
. La puoi anche usare (come facciamo qui) per
cancellare elementi da una lista. Così, del
unaLista[0]
cancella il primo elemento di unaLista
. Se
la lista fosse [1,2,3]
prima della cancellazione, dopo
sarebbe [2,3]
. Prima di continuare a spiegare i misteri dell'indiciamento degli elementi di liste, spiegherò brevemente l'esempio.
Questa è una versione dell'antico algoritmo noto come "Crivello di Eratostene". Considera un insieme (qui, una lista) di numeri candidati, e sistematicamente ne toglie i numeri che si sa non sono primi. Come lo si sa? Perchè sono prodotti di altri due numeri.
Iniziamo con una lista di candidati che contiene i numeri [2..999] -
sappiamo che 1 è primo, e vogliamo tutti i primi sotto 1000.
Abbiamo anche una lista detta risultati
che in ogni
momento contiene i risultati aggiornati sinora. All'inizio, questa
lista contiene solo il numero 1. Abbiamo anche una variabile detta
base
. A ogni iterazione ("giro") dell'algoritmo,
togliamo tutti i numeri che sono multipli di questo numero base
(che è sempre il più piccolo dei candidati). Dopo ciascuna
iterazione, sappiamo che il più piccolo numero restante è
primo (poichè tutti i numeri che erano prodotti di numeri più
piccoli sono stati rimossi - è chiaro?). Quindi, lo aggiungiamo
alla lista dei risultati, poniamo la nuova base a questo numero, e
lo togliamo dalla lista dei candidati (per non elaborarlo di nuovo).
Quando la lista di candidati è vuota, la lista dei risultati
conterrà tutti i primi. Furbo, no?
Cose a cui pensare: cos'ha di speciale la prima iterazione?
Qui la base è 2, però anch'essa è rimossa dal "crivello"...
perchè?
Perchè questo non succede alle altre basi? Possiamo essere sicuri che
prodotto
è sempre nella lista dei candidati quando
vogliamo toglierlo? Perchè?
Ora - e adesso? Ah sì... l'indiciamento. E l'affettamento. Questi
sono i modi per accedere ai singoli elementi delle liste Python. Hai
già visto il normale indiciamento in azione. È piuttosto semplice.
In effetti, ti ho detto tutto quel che hai bisogno di saperne, eccetto
una cosa: gli indici negativi contano dalla fine della lista.
Quindi,
unaLista[-1]
è l'ultimo elemento di
unaLista
, unaLista[-2]
è il penultimo,
e così via.
L'affettamento, invece, è una novità. È simile all'indiciamento, eccetto che con l'affettamento si può raggiungere un'intera fetta della lista, e non solo un singolo elemento. Come si fa? Così:
cibo = ["spam","spam","uova","salsicce","spam"]
print cibo[2:4]
# Stampa "['uova', 'salsicce']"
[Aggiungerò altro...]
(Ndt: è importante notare - e non è la prima volta che osserviamo questo tipo di comportamento in Python, che è infatti un linguaggio molto coerente...: anche nell'affettamento, il primo elemento indicato è incluso nella lista risultante, il secondo ne è escluso).10. Più astrazione - oggetti e programmazione orientata
agli oggetti
Ecco una frase di gran moda se mai ve ne
fu una: "Programmazione orientata agli oggetti".
Come suggerisce il titolo della sezione, la programmazione orientata agli oggetti (detta anche OOP, per "Object Oriented Programming") è solo un altro modo per astrarre dai dettagli. Le procedure astraggono le semplici istruzioni in operazioni più complesse dandogli un nome. Nell'OOP, non trattiamo in questo modo le operazioni, ma gli oggetti. (Ora, questa dev'essere proprio stata una grande sorpresa, hm?). Per esempio, se facessimo un programma per la cottura della spam, invece di scrivere un mucchio di procedure per trattare temperature, tempi, ingredienti ecc, potremmo raccoglierle in un oggetto spam. O forse, potremmo avere anche un oggetto forno e un oggetto orologio... ora, cose come la temperatura sarebbero attributi dell'oggetto spam, mentre il tempo potrebbe essere letto dall'oggetto orologio. E per far sì che il nostro programma faccia qualcosa, potremmo insegnare al nostro oggetto alcuni metodi; per esempio, il forno potrebbe saper cuocere la spam, ecc.
Ora - come fare questo in Python? Beh, non possiamo solo fare un oggetto direttamente. Invece di fare solo un forno, facciamo una ricetta che descrive come sono i forni. Una classe forno molto semplice potrebbe essere:
class Forno: def inserisciSpam(self, spam): self.spam = spam def ottieniSpam(self): return self.spam
Sembra molto strano, no...?
Cose nuove in questo esempio...
class
.
self
(o qualcosa del genere...). La ragione
(spero) ti sarà presto chiara.
miaSpam.temperatura = 2
, o dilbert.sii_carino()
.
Penso che alcune cose dell'esempio siano ancora poco chiare. Per esempio,
cos'è questa roba di
self
? E adesso che abbiamo una ricetta per oggetti
(cioè una classe), come ne facciamo un oggetto?
Vediamo prima quest'ultima cosa. Un oggetto è creato chiamando il nome della classe come se fosse una funzione:
mioForno = Forno()
mioForno
ora contiene un oggetto Forno
, detto
di solito una istanza della classe Forno
. Supponiamo
di avere fatto anche una classe
Spam
; allora potremmo fare qualcosa
come:
miaSpam = Spam() mioForno.inserisciSpam(miaSpam)
mioForno.spam
ora conterrebbe miaSpam
. Come?
Perchè, quando chiamiamo uno dei metodi di un oggetto, il primo
parametro, generalmente chiamato
self
, contiene sempre l'oggetto stesso. (Furbo, eh?)
Quindi, la riga
self.spam = spam
assegna all'attributo
spam
del corrente oggetto Forno
il valore del
parametro spam
. Nota che sono due cose diverse,
anche se si chiamano entrambe
spam
in questo esempio.
Risposta all'Esercizio 2
Ecco una versione molto
concisa
dell'algoritmo:
def euclide(a,b): while b: a,b = b,a % b return a
Riferimenti
[1] Ricetta per la Fiesta Spam Salad presa dal Libro Ricette Digitali della Hormel Foods