Moduli e funzioni

Contenuto del capitolo
  • Cosa sono i moduli
  • Funzioni come moduli
  • L'uso dei file per i moduli
  • Come scrivere funzioni e moduli propri

Che cosa è un modulo?

Il quarto elemento della programmazione è la programmazione modulare. In effetti non è un elemento strettamente necessario e usando gli elementi di cui abbiamo parlato fino ad ora è possibile scivere programmi assai complessi. Tuttavia quando un programma cresce di dimensioni diventa sempre più difficile tenere traccia di come funziona e di dove accadono le cose. Abbiamo dunque bisogno di un modo per avere una visione astratta che nasconda parte dei dettagli in modo da poterci concentrare sul problema da risolvere e non sul modo in cui funzionano i computer. Questo in qualche misura è già rappresentato dalle funzioni di base di Python e BASIC. Esse ci evitano di dover conoscere in dettaglio il funzionamento dell'hardware del computer, come leggere i singoli tasti della tastiera, ecc. Il ruolo della programmazione modulare è quello di consentire al programmatore di estendere le funzioni di base del linguaggio. Questa tecnica ci permette di raccogliere parti di programma sotto forma di moduli che possiamo poi inserire nei nostri programmi. Il primo strumento per la programmazione modulare è stata la subroutine ovvero un blocco di istruzioni a cui era possibile saltare (con logica simile all'istruzione GOTO già vista nel capitolo sulle istruzioni condizionali) ma tale che, al termine dell'esecuzione del blocco, il flusso di esecuzione ritornava al punto dal quale il blocco era stato chiamato. Questo specifico elemento per la programmazione modulare viene detto procedura o funzione. In Python ed in altri linguaggi di programmazione il termine modulo ha assunto un signifcato più specifico che vedremo fra breve, ma prima analizziamo più da vicino le funzioni.

Uso delle funzioni

Prima di vedere come creare funzioni ricordiamo come è possibile usare le molte, molte funzioni che fanno parte di qualunque linguaggio di programmazione (spesso chiamate collettivamente libreria). Abbiamo già visto alcune funzioni all'opera e ne abbiamo elencate altre nel capitolo sugli operatori. Adesso vedremo le caratteristiche che esse hanno in comune e come possiamo usarle nei nostri programmi.

La struttura di base di una funzione è la seguente:

unValore = unaFunzione(unArgomento, unAltro, ecc...)

Cioè ad una variabile viene assegnato un valore ricavato chiamando una funzione. La funzione può accettare zero o più argomenti che tratta come variabili interne. Le funzioni possono al loro interno chiamare altre funzioni. Vediamo alcuni esempi usando i nostri linguaggi per capirne il funzionamento:

BASIC: MID$(str$,n,m)

Questa funzione scrive m caratteri della stringa str$ a partire dall'n-esimo. (Ricordate che in BASIC i nomi che terminano con "$" indicano le stringhe).

time$ = "GIORNO POMERIGGIO ANNO"
PRINT "Buon";MID$(time$,7,10)

Questa istruzione scrive "Buon POMERIGGIO".

BASIC: ENVIRON$(str$)

Questa riporta il valore della Variabile di Ambiente specificata da str$.

PRINT ENVIRON$("PATH")

Stampa il valore corrente di PATH specificato per il DOS (di solito da un comando nel file autoexec.bat).

Tcl: llength L

Riporta la lunghezza della lista L

set a {"primo" "secondo" "terzo"} # Una lista di tre elementi
puts [llength $a]  # Il risultato è "3"

Nota: In Tcl quasi tutti gli elementi sono funzioni (o, per usare una terminologia più usata, comandi). Questo lo porta ad avere una sintassi un po' strana, ma rende assai semplice per il computer leggere i programmi Tcl. Questo è importante in quanto Tcl sta per Tool Control Language (Linguaggio per il controllo di strumenti, N.d.t,) ed è stato progettato per essere incorporato in altri programmi come linguaggio di macro, analogamente al Visual Basic for Applications(VBA) prodotto dalla Microsoft. Anche Python può essere incorporato in modo analogo, ma Tcl è unico in quanto è stato progettato per primo e con la possibilità di incorporamento come caratteristica principale.

Python: pow(x,y)

x = 2   #  usiamo 2 come base delle potenze
for y in range(0,11):
   print pow(x,y)    # si eleva 2 alla potenza y, con y 0-10)

Qui abbiamo generato valori per y da 0 a 10 ed abbiamo chiamato la funzione di base pow() passando due argomenti: x ed y. Ad ogni chiamata della funzione i valori correnti di x ed y vengono sostituiti nella chiamata e viene scritto il risultato.

Nota: L'operatore esponente, ** è equivalente alla funzione pow().

Python: dir(m)

Un'altra utile funzione di Python è dir che, chiamata con il nome di un modulo per argomento, riporta una lista di nomi validi (che spesso sono nomi di funzione) all'interno del modulo. Fate una prova con le funzioni di base:

print dir(__builtins__)

Nota: Prima di usare la funzione in qualunque altro modulo è necessario che il modulo sia importato con import, altrimenti Python si lamenterà di non conoscere il nome del modulo.

Prima di andare avanti è opportuno trattare un po' più in dettaglio i moduli in Python.

Come si usano i moduli

Python è un linguaggio estremamente estensibile (anche Tcl lo è, comunque) in quanto consente di aggiungere nuove funzionalità mediante l'importazione di moduli. Fra poco mostreremo come creare nuovi moduli, ma per il momento limitiamoci ad usare alcuni dei moduli standard distribuiti insieme a Python.

sys

Abbiamo già incontrato il modulo sys quando abbiamo usato la sua funzione exit per uscire da Python. Il modulo fornisce anche molte altre utili funzioni. Per poterle utilizzare occorre premettere l'istruzione import sys:

import sys # Per rendere disponibili le funzioni
sys.exit() # Si premette alla funzione il nome del modulo "sys"
Se sappiamo che la funzione sarà usata molte volte e che non ci saranno altre funzioni con lo stesso nome importate o create in altro modo, possiamo anche specificare l'importazione così:
from sys import *  # importa tutti i nomi definiti in sys
exit() # possiamo usare la funzione senza il prefisso "sys"

Altri moduli ed il loro contenuto

Allo stesso modo possono essere importati ed usati altri moduli, compresi quelli da voi creati. Fra poco vedremo come farlo, ma prima ecco una breve panoramica di alcuni dei moduli standard di Python e di alcune delle funzioni che offrono:

Nome del moduleDescrizione
sys Consente l'interazione con il sistema Python:
  • exit() - uscita
  • argv - accesso agli argomenti della linea di comando.
  • path - accesso al percorso di sistema
  • ps1 - cambia il prompt ">>>" di Python!
os Consente l'interazione con il sistema operativo
  • open - apre un file
  • system - esegue un comando del sistema operativo
  • mkdir - crea una directory
  • getcwd - riporta la directory corrente
string Consente la manipolazione di stringhe
  • atoi/f/l - converte una stringa in un valore intero / a virgola mobile / intero esteso
  • find - estrae una sottostringa
  • split - suddivide una stringa in "parole"
  • upper/lower - conversione maiuscole/minuscole
re Consente la manipolazione di stringhe mediante espressioni regolari, come in Unix.
  • search - trova un elemento all'interno di una stringa
  • match - trova un elemento nella parte iniziale di una stringa
  • split - suddivide in campi separati da un dato elemento
  • sub,subn - sostituzione di stringhe.
math Consente l'accesso a molte funzioni matematiche
  • sin,cos etc - funzioni trigonometriche
  • log,log10 - logaritmi naturali e decimali
  • ceil,floor - troncamento per eccesso o per difetto.
  • pi, e - le costanti naturali
time funzioni relative al tempo (e alla data)
  • time - restituisce il tempo corrente (in secondi [a partire da una data inziale prestabilita (epoch), N.d.T.])
  • gmtime - converte il tempo in secondi in UTC (GMT)
  • localtime - converte nel tempo locale
  • mktime - inversa di localtime
  • sleep - sospende il programma per n secondi

Queste rappresentano solo la punta dell'iceberg. Ci sono decine di moduli forniti insieme a Python e molti altri che potete scaricare dalla rete. (Un buon punto di partenza è il Vaults of Parnassus). Cercate nella documentazione per scoprire come creare applicazioni per Internet, grafiche, costruire database, ecc.

Ciò che è importante capire è che la maggior parte dei linguaggi di programmazione hanno questi tipi di funzione, o incorporate nel linguaggio o come librerie di base. Verificate sempre nella documentazione prima di scrivere una nuova funzione: potrebbe essere già pronta! Questo introduce elegantemente l'argomento seguente ...

Come definire le funzioni

Adesso sappiamo come usare le funzioni esistenti, ma come possiamo crearne di nuove? Semplicemente dichiarandole. Ovvero scrivendo un'istruzione che indica all'interprete che vogliamo definire un blocco di istruzioni che dovrà essere inserito a richiesta in un qualunque altro punto del programma.

Creiamo quindi una funzione che scrive la tabellina della moltiplicazione per un qualunque valore passato come argomento. In BASIC si presenta così:

SUB TABEL (N%)
FOR I = 1 TO 12
    PRINT I; "x"; N%; "="; I * N%
NEXT I
END SUB

e possiamo richiamarla così:

PRINT "Ecco la tabellina del 7..."
TABEL(7)

Nota: Abbiamo definito un parametro di nome N% ed abbiamo passato un argomento di valore 7. La variabile locale N% all'interno della funzione, al momento della chiamata, ha assunto il valore 7. Possiamo definire tutti i parametri che vogliamo nella definizione della funzione ed il programma chiamante deve fornire un valore per ciascun parametro. Alcuni linguaggi di programmazione consentono di definire valori di "default" (valori predefiniti, N.d.t.) per i parametri, in modo che se non viene fornito esplicitamente un valore l'argomento prende il valore predefinito. Lo vedremo in Python fra breve.

In Python la funzione TABEL appare così:

def tabel(n):
    for i in range(1,13):
        print "%d x %d = %d" % (i, n, i*n)

e viene chiamata così:

print "Ecco la tabellina del 9..."
tabel(9)

Notate che queste funzioni non restituiscono alcun valore (sono in effetti forme che alcuni linguaggi chiamano procedure). Infatti possiamo notare che la versione BASIC utilizza la parola chiave SUB invece che FUNCTION. La parola è un'abbreviazione di subroutine, un termine poco usato che risale al tempo della programmazione in Assembler e che in BASIC indica una funzione che non restituisce alcun valore. Python invece utilizza il termine def che sta per "define" e presuppone che le istruzioni che seguono compongano una funzione.

Ricordate che abbiamo citato l'uso di valori predefiniti? Un'utile applicazione di questa caratteristica si potrebbe avere in una funzione che restituisce il giorno della settimana. Se la chiamiamo senza specificare un argomento si riferisce alla data di oggi, altrimenti possiamo specificare un numero che indica un qualunque giorno. Ad esempio:

# valore di giorno -1 => oggi
def GiornoDellaSettimana(Giorno = -1):
    Settimana = ['Lunedi','Martedi',
                 'Mercoledi','Giovedi', 
                 'Venerdi', 'Sabato', 'Domenica']
                
    # verifica se il giorno e' quello predefinito        
    if Giorno == -1:
        # Si utilizzano le funzioni del modulo time per ricavare il tempo
        # vedere la tavola sopra e la documentazione del modulo
        import time
        Tempo = time.localtime(time.time())
        Giorno = Tempo[6]
    return Settimana[Giorno]

Nota: Il modulo time serve solo quando si utilizza il valore predefinito del giorno, quindi usiamo l'operazione import solo quando è necessario. Questo risulta in un lieve aumento delle prestazioni se non dobbiamo mai usare il valore predefinito.

Adesso possiamo chiamare la funzione come segue:

print "Oggi è %s" % GiornoDellaSettimana()
# Ricordiamo che nella programmazione si comincia 
# a contare solitamente da 0 e che in questo caso assumiamo che il primo
# giorno della settimana sia Lunedi.
print "Il terzo giorno è:%s" % GiornoDellaSettimana(2)

Torniamo nuovamente alle tabelline ....

Supponiamo di voler definire una funzione che riporta una tabellina come vettore di numeri. In BASIC si presenta così:

FUNCTION TABEL% (N%)
    DIM VALORI(12) AS INTEGER
    FOR I = 1 to 12
        VALORI(I) = I*N%
    NEXT I
    RETURN VALORI
END FUNCTION

In Python:

def valori(n):
    # crea una lista vuota
    valori = []  
    for i in range(1,13):
        valori.append(i*n)
    return valori

Questa è una funzione piuttosto stupida in quanto è più facile calcolare i*n quando ce n'è bisogno, ma speriamo di aver reso l'idea. Un esempio più utile potrebbe essere una funzione che conta le parole in una stringa. Potrebbe essere usata, ad esempio, per contare le parole in un file, sommmando i valori della funzione riga per riga.

Il codice di tale funzione potrebbe essere:

def n_parole(s):
    lista = split(s) # lista i cui elementi sono le parole
    return len(lista) # restituisce il numero di elementi della lista

for riga in file:
    totale = totale + n_parole(riga) # somma i totali per ogni riga
print "Il file contiene %d parole" % totale

Se provate ad eseguire il programma vedrete che non funziona. Abbiamo usato una tecnica di progetto assai comune che consiste nell'abbozzare la forma del programma senza preoccuparsi di usare le istruzioni in modo del tutto corretto. Questo viene chiamato normalmente pseudocodice o, con un termine più formale, Linguaggio per la descrizione di programmi (PDL) (abbreviazione di "Program Description Language", N.d.t.).

Dopo che avremo parlato della manipolazione dei file e delle stringhe, un po' più avanti, torneremo a questo esempio per renderlo davvero funzionante.

Funzioni in Tcl

Anche in Tcl possiamo creare funzioni, ovviamente, utilizzando l'istruzione proc come nell'esempio seguente:

proc tabel {m} {
    for {set i 1} {$i <= 12} {incr i} {
        lappend risultato [expr $i * $m]
	}
    return $risultato
}

Notate che usando l'istruzione lappend in Tcl automaticamente viene creata una lista di nome risultato quando si aggiunge per la prima volta un elemento.

Facciamo attenzione

Tcl tratta le funzioni in modo un po' differente dagli altri linguaggi. Avrete infatti notato che abbiamo chiamato le funzioni di base di Tcl istruzioni. Questo perché in Tcl ogni istruzione che viene digitata al prompt è in effetti una chiamata di funzione. La maggior parte dei linguaggi dispongono di un insieme di parole chiave come for, while, if/else e così via. In Tcl tutte queste parole chiave sono comandi o funzioni. Questo ha un effetto interessante, ed assai potente, ma che può facilmente generare confusione: la possibilità di ridefinire le strutture di controllo, come nell'esempio seguente.

set i 3
while {$i < 10} {
    puts $i
    set i [expr $i + 1]
    }

Come previsto questo scrive i numeri da 3 a 9 (10 meno 1). Ma proviamo ora a definire la nostra versione dell'istruzione while:

proc while {x y} {
  puts "Questo e' il mio while"
}

set i 3
while {$i < 10} {
    puts $i
    set i [expr $i + 1]
    }
    

Questo non fa altro che visualizzare il messaggio "Questo e' il mio while". L'espressione e la sequenza di comandi sono ignorate perché Tcl li tratta come parametri della funzione while e la funzione while li accetta, ma li ignora! Abbiamo quindi visto come definire le funzioni in Tcl e come farne un cattivo uso realizzando programmi destinati a confondere totalmente le idee, cosa da non fare senza una ragione veramente buona.

Come creare nuovi moduli

Abbiamo visto come creare nuove funzioni e come richiamarle da altri punti di un programma. Questo è importante perché può farci risparmiare tempo di battitura e, cosa più importante, rende i programmi più facili da leggere perché, una volta definita una funzione che racchiude certe caratteristiche, possiamo dimenticare molti dettagli del suo funzionamento. (Questo principio di racchiudere gli aspetti complessi di un programma dentro le funzioni viene chiamato data hiding (mascheramento delle informazioni, N.d.T.) per ragioni abbastanza ovvie). Ma come possiamo usare le funzioni in altri programmi? Creando un modulo.

I moduli in Python

Un modulo in Python non è altro che un semplice file contenente istruzioni Python. Di solito queste istruzioni sono definizioni di funzione. Quindi, quando scriviamo:

from sys import *

in effetti ricopiamo il contenuto del file sys.py dentro il nostro programma, quasi come con una operazione "taglia e incolla" (non è proprio così, ma rende l'idea). Infatti in alcuni linguaggi di programmazione (ad esempio C++) il traduttore semplicemente copia i file dei moduli nel programma corrente secondo le necessità.

Ricapitolando, per creare un modulo occorre creare un file Python che contiene le funzioni che vogliamo riutilizzare all'interno di altri programmi. Quindi semplicemente importiamo il nostro modulo, esattamente come abbiamo fatto con i moduli di base. È piuttosto facile, vediamolo in pratica.

Copiate la funzione mostrata sotto in un file e salvatelo con il nome tabellina.py

def scrivi_tabella(moltiplicatore):
    print "--- Ecco la tabellina del %d ---" % moltiplicatore
    for n in range(1,13):
        print "%d x %d = %d" % (n, moltiplicatore, n*moltiplicatore)

Quindi al prompt di Python scrivete:

>>> import tabellina
>>> tabellina.scrivi_tabella(12)

così avete creato un modulo e lo avete usato.

Nota Importante: Se non avete lanciato Python dalla stessa directory che contiene il file tabellina.py, Python potrebbe non essere in grado di trovare il file, generando quindi un errore. Se questo avviene è possibile creare una variabile di ambiente chiamata PYTHONPATH, contenente l'elenco delle directory nelle quali ricercare i moduli (oltre ai moduli base forniti da Python).

La creazione di una variabile di ambiente è un'operazione che dipende dal sistema operativo, assumiamo che la conosciate già o che sappiate dove cercare la spiegazione.

Moduli in BASIC ed in Tcl

Cosa succede in BASIC? La cosa è più complessa... In QBASIC ed in altre varianti più antiche non esiste un vero concetto di modulo. Dovrete fare tutto a mano, utilizzando l'editor di testi per estrarre parti di vostri programmi precedenti ed inserirle in quello corrente. In Visual Basic invece esiste il concetto di modulo ed è possibile caricare un modulo per mezzo del menu File|Apri modulo... dell'ambiente di sviluppo (Integrated Development Environment - IDE). Ci sono alcune restrizioni relativamente a che cosa può essere fatto all'interno di un modulo BASIC, ma dato che non useremo Visual Basic per questo corso non proseguiremo nella descrizione. (Nota: esiste una versione ridotta di Visual Basic conosciuta come CCE, COM Control Edition, disponibile gratuitamente presso il sito Web della Microsoft se siete in vena di esperimenti. Inoltre Windows 98, 2000 e IE5 comprendono tutti una versione ridotta di VB, VBScript, che può essere utilizzata in file che terminano per .vbs).

Infine Tcl segue, come sempre (!), una strada un po' fantasiosa ma comunque interessante relativamente al riutilizzo di moduli (o, come vengono comunemente chiamati, librerie).

L'approccio più semplice consiste nel creare un file contenente funzioni Tcl esattamente come in Python e successivamente usare nel vostro programma il comando source con il nome del file. Questo richiede all'interprete di leggere il file e rendere disponibili all'uso i programmi in esso contenuti. Ma c'è un'opzione più interessante:

Potete anche creare i vostri file come detto sopra, metterli tutti in una cartella (o directory) e quindi usare il comando mk_index. Questo crea un indice di tutte le funzioni ed i file della cartella. Poi nel vostro programma potete semplicemente chiamare la funzione necessaria e quando l'interprete Tcl verifica che la funzione non è definita cercherà automaticamente nel file indice. A questo punto userà il comando source sul file relativo e quindi eseguirà la funzione.

In seguito al comando source la funzione resta disponibile e quindi questa tecnica provoca solo una piccola diminuzione di prestazioni. L'unica controindicazione consiste nel fatto che il programmatore deve evitare di avere più funzioni con lo stesso nome. Questa caratteristica di Tcl viene detta autoloading (Caricamento automatico, N.d.t.).

Nel prossimo capitolo tratteremo dei file e dell'elaborazione di testi e quindi, come preannunciato, rivedremo il problema del conteggio delle parole in un file. In realtà per comodità finiremo col creare un modulo di funzioni per l'elaborazione di testi.

 
Promemoria
  • Le funzioni sono una forma di moduli
  • Le funzioni riportano valori, le procedure no.
  • I moduli Python di solito consistono di definizioni di funzioni contenute in un file.
  • In Python per creare una nuova funzione si utilizza la parola chiave def.
  • In Basic si usano SUB o FUN, proc in Tcl.

 
Precedente  Indice  Successivo 


Se avete domande o suggerimenti relativi a questa pagina mandate un e-mail all'autore: alan.gauld@yahoo.co.uk o al traduttore italiano: lfini@arcetri.astro.it