Moduli Python
Il capitolo sui moduli Python è probabilmente il più importante di tutti! Python è diventato uno dei linguaggi più utilizzati al mondo proprio perché grazie ai suoi moduli può arrivare in maniera veloce a gestire qualunque aspetto della programmazione: basta scegliere il modulo giusto!!!
Per organizzare al meglio il lavoro, l'argomento Moduli Python
è spalmato su 3 capitoli:
-
In questo capitolo vedremo come si crea un modulo e come si utilizza.
-
Nel capitolo Python Standard Library andremo a vedere i moduli predefiniti, ovvero quelli già disponibili senza fare null'altro in qualunque installazione Python: in questo caso il focus si sposta sull'utilizzo di moduli prodotti da altri, sulla consultazione della documentazione, sull'utilizzo dei moduli Python di base.
-
Nel capitolo PyPi ci occuperemo di reperire, installare e utilizzare alcuni dei moduli disponibili su Internet, precisamente nel
Python Package Index
, per ottenere in un attimo uno o più moduli che implementano una funzionalità per noi interessante e/o utile per il software che vogliamo sviluppare.
Al lavoro!
Come accennato, in questo capitolo ci occuperemo di implementare un modulo scrivendo tutto il codice, investigando i concetti di base e procedendo ai test semplici delle funzionalità implementate.
Istruzione import
In Python la clausola import si utilizza per rendere disponibile il codice in un modulo in un altro. Questo concetto rende semplice l'organizzazione del codice in senso logico, sia dal punto di vista dei file che dal punto di vista dell'organizzazione globale del codice.
Dal punto di vista dei file, ogni modulo è ben organizzato perché contiene codice coerente: un ipotetico modulo numeri
conterrà funzioni che lavorano coi numeri, un modulo statistiche
contiene funzioni per il calcolo statistico, etc..
Dal punto di vista dell'organizzazione globale del codice, l'importazione di un modulo genererà un namespace
che manterrà semplice la gestione del codice.
Capisco che il secondo punto di vista necessita di un ulteriore chiarimento: dal punto di vista intuitivo, noi abbiamo già usato il modulo random
per le nostre liste numeriche. Allora
scriviamo:
import random
# per accedere alle funzioni del modulo random, dobbiamo scrivere modulo.funzione
intero = random.randint(1,100)
Questa organizzazione imposta dall'import (ovvero modulo.funzione
) permette di capire chiaramente che la funzione randint deriva dal modulo random e non è stata definita all'interno
di questo modulo. Quando le importazioni saranno di più e i moduli scritti da noi più lunghi, questa cosa inizierà ad essere molto utile.
Inoltre il namespace
indotto preserva le funzioni importate da un altro importante problema: se molte persone diverse scrivono codice potrebbe tranquillamente capitare che due funzioni
scritte da persone diverse, su moduli diversi, abbiano lo stesso nome. Il namespace
impedisce confusione in questo caso.
Nomi dei moduli
Tutte le persone hanno un nome che le identifica (ad esempio il mio nome è Andrea), ma quando le persone parlano di se stesse usano la parola io
(io mi chiamo Andrea).
E fin qui mi sembra tutto semplice.
Abbiamo detto finora (e nel dubbio, lo ripeto con chiarezza) che anche i moduli, ovvero i file Python con estensione .py
, hanno un nome, che dipende dal nome del file stesso:
ad esempio, il file pippo.py
definisce il modulo di nome pippo
. Ogni volta che definite un modulo, Python inizializza alcune variabili speciali, fra cui la variabile __name__
che contiene il nome del modulo (fra un attimo faccio un esempio).
Così come le persone, parlando di se stesse, dicono io, i moduli, al loro interno non utilizzano il loro nome, ma utilizzano la parola __main__
.
Cerchiamo di chiarire subito questo primo concetto, il resto verrà naturalmente di conseguenza:
# file pippo.py
# la variabile __name__ si riferisce al nome del modulo pippo
# essendo al suo interno, conterrà la parola "__main__"
print(__name__)
# file ciccio.py
# importo il modulo pippo, dell'esempio 1
# importando il modulo, andrò ad eseguirlo. la print sopra (eseguita all'esterno del modulo pippo)
# scriverà il suo nome: "pippo".
import pippo
# la variabile __name__ qui sotto si riferisce al nome del modulo ciccio
# essendo al suo interno, conterrà la parola "__main__"
print(__name__)
# la variabile __name__ qui sotto si riferisce al nome del modulo pippo
# NON essendo dentro al modulo pippo, conterrà il suo nome proprio, ovvero "pippo"
print(pippo.__name__)
Tutto qui
Testing
Dalle considerazioni fatte nei precedenti capitoli, vorrei farvi capire una tecnica molto utilizzata in ambito Python per l'esecuzione dei moduli e i test delle funzioni in essi contenute.
La strategia è questa:
- scrivo il modulo con la definizione delle funzioni che mi interessano
- faccio delle prove per assicurarmi che tutto... funzioni! (faccio i test!!!) in fondo al file, dentro un
if __name__ == "__main__"
- Se eseguo direttamente il modulo con le funzioni, l'if mi permette di svolgere i test (e verificare che tutto funzioni correttamente)
- Se importo il modulo in un altro contesto, il suo nome NON sarà "main" e i test non saranno svolti, permettendo di importare solo le funzioni!
Da questa spiegazione, deriva questa modalità di scrittura dei moduli con funzioni:
# file prova.py
def molt(fatt1:float,fatt2:float) -> float:
"""
prende i valori nei parametri fatt1,fatt2 e ritorna il prodotto fatt1 * fatt2
Ad esempio: molt(4,5) ritorna 20
Parametri
---------
fatt1
un numero reale, il primo fattore della moltiplicazione
fatt2
un numero reale, il secondo fattore della moltiplicazione
"""
return fatt1 * fatt2
# questa parte NON sarà eseguita all'esterno del modulo "prova"
if __name__ == "__main__":
x = 5
y = 4
print("x:",x)
print("y:",y)
print( f"molt({x},{y}):{molt(x,y)}" )
# ... e così via...
Da ora in poi scriveremo così i nostri moduli e in questo modo faremo tutti gli esercizi che seguono. Questo ci permetterà di definire un modus operandi logico e professionale, che ci tornerà enormemente utile quando le cose diventeranno inevitabilmente più complicate.
Adesso, sotto con gli esercizi!
Esercizi
Nota
Ognuno dei seguenti esercizi deve essere implementato in un unico file, nominato con il nome indicato nell'intestazione dell'esercizio, completo di documentazione e di (almeno) 3 casi di test per ognuna delle funzioni implementate!!!
Esercizio 601: modulo "SequenzeNumeriche"
minoriDiUnElemento
Creare una funzione che, data una sequenza numerica (tupla o lista) e un
numero qualsiasi, conta quanti numeri nella sequenza sono minori del
numero.
sommaElementi
Creare una funzione che, data una sequenza numerica (tupla o lista),
restituisce la somma dei numeri della sequenza.
mediaElementi
Creare una funzione che, data una sequenza numerica (tupla o lista),
restituisce la media aritmetica dei numeri della sequenza.
Esercizio 602: modulo "ManipolazioneStringhe"
lunghezzaStringa
La funzione prende una stringa come parametro e ritorna il numero di
caratteri di cui è composta (la sua lunghezza)
contaLettera
La funzione prende una stringa e una lettera come parametro e ritorna il
numero di volte in cui la lettera è presente all'interno della stringa
tutteMaiuscole
La funzione prende una stringa come parametro e ritorna la stringa
trasformata in maiuscolo
tutteMinuscole
La funzione prende una stringa come parametro e ritorna la stringa
trasformata in minuscolo
invertiMaiuscoleMinuscole
La funzione prende una stringa come parametro e ritorna la stringa con
maiuscole e minuscole invertite.
inizialiMaiuscole
La funzione prende una stringa come parametro e ritorna la stringa
trasformata in minuscolo con le iniziali di ogni parola maiuscole
Esercizio 603: modulo "PianoCartesiano"
quadrante
La funzione prende due numeri x, y che rappresentano le coordinate del
punto P nel piano cartesiano e restituisce un numero corrispondente al
quadrante nel quale esso si trova, ovvero un numero fra 1 e 4.
Restituisce 0 nel caso che il punto sia su uno degli assi cartesiani.
distanzaOrigine
La funzione prende due numeri x, y che rappresentano le coordinate del
punto P nel piano cartesiano e restituisce la distanza del punto P
dall'origine degli assi, ovvero dal punto O di coordinate (0,0).
distanzaFraDuePunti
La funzione prende quattro numeri xP, yP, xQ, yQ che rappresentano le
coordinate dei punto P e Q nel piano cartesiano e restituisce la
distanza fra loro.
Esercizio 604: modulo "CifreNumeriche"
unità
La funzione prende un numero come parametro e restituisce la cifra delle
unità. Ad esempio unita(23) restituisce 3, unita(8174.56) restituisce 4.
decine
La funzione prende un numero come parametro e restituisce la cifra delle
decine. Ad esempio decine(23) restituisce 2, decine(8174.56) restituisce 7.
centinaia
La funzione prende un numero come parametro e restituisce la cifra delle
centinaia. Ad esempio centinaia(23) restituisce 0, centinaia(8174.56)
restituisce 1.
migliaia
La funzione prende un numero come parametro e restituisce la cifra delle
migliaia. Ad esempio migliaia(23) restituisce 0, migliaia(8174.56)
restituisce 8.
decimi
La funzione prende un numero come parametro e restituisce la cifra dei
decimi. Ad esempio decimi(23) restituisce 0, decimi(8174.56) restituisce
5.
centesimi
La funzione prende un numero come parametro e restituisce la cifra dei
centesimi. Ad esempio centesimi(23) restituisce 0, centesimi(8174.56)
restituisce 6.
Esercizio 605: modulo "FunzioniNumeriche"
sommaDivisori
La funzione prende un numero intero come parametro e restituisce la
somma dei suoi divisori propri (ovvero dei divisori minori del numero
stesso)
listaDivisori
La funzione prende un numero intero come parametro e restituisce la
lista dei suoi divisori propri (ovvero dei divisori minori del numero
stesso)
isPrime
La funzione prende un numero intero come parametro e restituisce True se
il numero è primo, false altrimenti. (sugg: se un numero è primo il suo
unico divisore proprio è 1...)
perfetto
La funzione prende un numero intero come parametro e restituisce True se
il numero è perfetto, False altrimenti (un numero si dice perfetto se e
solo se è uguale alla somma dei suoi divisori propri)
nthPrime
La funzione prende un numero intero come parametro e restituisce
l'ennesimo numero primo. Ad esempio dato 3, la funzione restituisce 5
perché, essendo i numeri primi 2, 3, 5, 7, 11, etc... 5 è il terzo
numero primo.
semiPrimo
La funzione prende un numero intero come parametro e restituisce True se
il numero è semiprimo, False altrimenti. Un numero si dice semiprimo se
è esprimibile come prodotto di due numeri primi. Ad esempio 6 = 2 per 3 è
semiprimo, 7 = 7 per 1 non è semiprimo, infatti 1 non è primo.