lunedì 19 aprile 2010

Ancora Python

È ampiamente documentata in letteratura la tendenza del colpevole a tornare sul luogo del misfatto, così eccomi qua. Oggi voglio illustrare uno script non banale come il precedente. E sarà fatta in due versioni: la prima triviale, quasi brutale che poi verrà riscritta come si deve. Non conoscendo la classe l'esposizione sarà per niubbi (n00bs), anche il Trota, se capitasse qui, capirebbe tutto; ma solo per questa volta, dalla prossima...

La prima versione ci serve per introdurre alcuni elementi fondamentali della programmazione Python. Quelli che hanno esplorato i link forniti nella puntata precedente e si sono magari scaricati il manuale sapranno già tutto, portino pazienza, se vogliono possono andarsi a fare un giro, è primavera, ci sono un sacco di ragazze attraenti! (Per quel che ne so continua a esserci una preponderante preponderanza di maschietti in questo campo, chissà?).
Una delle necessità che tutti abbiamo è quella di calcolare i fattoriali. da oggi non sarà più un problema, iniziamo subito con la prima versione triviale.

Il fattoriale di N, scritto N! è definito come:
per N = 0 e N = 1 -> N! = 1
per N > 1 -> N! = il prodotto dei numeri interi da 1 a N. Ad esempio 3! = 1 * 2 * 3 = 6.
Allora, con il nostro editor preferito (io uso Geany, va bene anche Gedit o qualunque altro di vostro gradimento, sì anche Emacs) scriviamo:

#!/usr/bin/env python
# -*- coding: ISO-8859-1 -*-

# calcolo del fattoriale
# prima versione

N = 5 # numero di cui vogliamo calcolare il fattoriale
fact = 1
for n in range(1, N + 1):
fact = fact * n
print "il fattoriale di", N, "è", fact, "\n"

Salviamo il file e eseguiamolo, otterremo qualcosa come:

$ python f1.py
il fattoriale di 5 è 120

$

Se modifichiamo il file sostituendo N = 5 con N = 7 e eseguiamo otterremo 5040 al posto di 120. OK, adesso abbiamo uno strumento potentissimo che ci libera dall'annoso problema del calcolo del fattoriale di qualunque numero sensato.
Ma come funziona? Ecco adesso lo spiego (ci provo).
La prima riga #!/usr/bin/env python si chiama shebang e deve davvero essere la prima riga del file, e iniziare in colonna 1. Dice alla shell di Linux con che interprete il file dev'essere eseguito, nel caso che si renda eseguibile il nostro script (come abbiamo fatto nella prima puntata). Per Windows questa riga viene semplicemente ignorata, per il motivo che sarà chiaro tra un attimo.
La seconda riga # -*- coding: ISO-8859-1 -*- dice di usare il set di caratteri ISO per l'Europa occidentale, ci serve per i caratteri accentati normali, nel nostro caso la "è". Deve essere la prima o la seconda linea del file.
Segue una riga vuota, ignorata dall'interprete. Poi due righe che iniziano con "#": sono commenti, tutta la riga da # compreso fino alla fine viene trascurata dall'interprete. È possibile iniziare il commento anche dopo un'istruzione, come facciamo nella riga successiva.
La riga N = 5 # ... assegna alla variabile N il valore 5. In Python non c'è bisogno di dichiarare le variabili e il loro tipo, è automatico definito dal contesto. Non è peraltro possibile referenziare una variabile senza averle assegnato un valore.
fact = 1: idem come sopra; più interessante la riga successiva for n in range(1, N + 1):. Dove "for" è la parola riservata che definisce il ciclo, come in C, Basic, Pascal; "n" è il contatore del ciclo, assumerà i valori 1, 2, ..., 5 e noi lo useremo nella riga successiva; "in range( ... )" definisce l'intervallo (numerico in questo caso) del ciclo, cioè i valori da assegnare al contatore "n"; la definizione del ciclo deve essere completata con ":" (che io dimentico spesso). Una caratteristica strana del ciclo Python è che il limite superiore NON viene eseguito, abbiamo pertanto dovuto scrivere N + 1 e non N come sarebbe sembrato naturale: il motivo sarà chiaro quando tratteremo le liste.
Altra cosa da notare è che le variabili "n" e "N" sono diverse, chi viene da Windoze si ritenga avvisato!
Dopo la riga di definizione del ciclo segue il blocco del ciclo. I linguaggi moderni adottano quasi tutti la notazione del C racchiudendo il blocco tra { e }. Python no. Il blocco dev'essere rientrato (indentato) rispetto alla sua definizione. Ci sono due modi per effettuare il rientro: degli spazi (quasi sempre 4) o un segno di tabulazione (tab). Non si possono mischiare, si deve decidere prima a quale scuola si appartiene e rimanere fedeli.
Nel nostro caso il blocco consiste di una sola riga fact = fact * n, che va letta "assegna alla variabile fact il prodotto della variabile fact per il contatore n". L'ho scritta così perché siamo nuovi, un programmatore appena-appena svezzato scriverebbe fact *= n, con notevole risparmio nel consumo dei polpastrelli dei suoi diti (sì, sempre derivato dal C).
Finalmente, uscito dal ciclo (notato che non c'è più l'indentazione) l'istruzione print "il fattoriale di", N, "è", fact, "\n" fa scrivere sul terminale la frase "il fattoriale di 5 è 120" seguito da un a-capo. Allora "print" è la parola riservata per scrivere a terminale; le stringhe tra " vengono scritte esattamente come sono (o quasi), le variabili vengono sostituite dai loro valori. I vari pezzi devono essere separati da ",".
Volendo l'istruzione poteva essere print 'il fattoriale di', N, 'è', fact, '\n': i segni ' e " sono intercambiabili, solo il primo usato è vincolato, l'altro può essere usato liberamente.
Ma c'è ancora una cosa da notare: "\n" è la sequenza di escape che viene interpretata come "a-capo". Altre sequenze di escape sono \t -> tab, \\ -> \. E poi ogni carattere preceduto da \ perde il suo significato speciale, posso quindi scrivere \' e \" all'interno di una stringa indipendentemente dal delimitatore usato. Qui gli utenti Windows faranno casino, lo sento.

Conclusione:
Abbiamo esplorato alcuni aspetti del Python, applicato a un caso pratico. E funziona tutto, ma è ancora elementare. E brutto: rileggiamo la definizione di fattoriale, sperando che i matematici eventualmente presenti siano comprensivi.
Loro N! l'avrebbero definito così:
per N = 0 e N = 1 -> N! = 1
per N > 1 -> N! = N * (N-1)!
definiscono cioè il fattoriale in funzione del fattoriale. E la cosa gli piace talmente tanto che gli hanno dato un nome: ricorsione. Propongo che la prossima puntata consideri se possiamo affrontare il nostro lavoro ricorsivamente.

2 commenti:

  1. Non capisco nulla di ciò che scrivi ma difenderò il tuo modo di dirlo fino alla morte. :-)

    RispondiElimina
  2. Grazie Pop, la citazione voltairiana applicata a me mi piace. Ma hai provato a fare l'esercizio impegnandoti? Io sono sicuro che ce la puoi fare. E nel post successivo ci saranno tante cose e si darà in qualche misura per scontato che gli allievi siano smarts.

    RispondiElimina

Attenzione: I commenti a vecchi post potrebbero essere moderati