Un modulo in Python permette di organizzare in modo logico il codice. Raggruppare codice correlato in un modulo rende il codice più facile da capire e da usare. Un modulo è un oggetto Python con attributi arbitrari che si possono referenziare.

Semplicemente, un modulo è un file che contiene codice scritto in Python. Un modulo può definire funzioni, classi e variabili.

Esempio

Il codice Python per un modulo chiamato “prova” tipicamente risiede in un file chiamato “prova.py”. Qui di seguito un esempio di modulo chiamato ‘prova.py’:

def stampa( varz ):
   print("Ciao : ", varz)
   return

L’istruzione import

Si può usare qualsiasi codice sorgente Python come modulo eseguendo un’istruzione import dal file principale. L’import ha questa sintassi:

import module1 [, module2[,... moduleN]]

Quando l’interprete incontra l’istruzione import, importa il modulo se presente nel percorso di ricerca. Un percorso di ricerca è una lista di directory in cui l’interprete va a cercare il modulo. Per esempio, per importare il modulo prova.py visto sopra sarà sufficiente fare:

import prova #importa il modulo prova
 
prova.stampa("Rocco") #chiamiamo una funzione definita nel modulo

che stamperà:

Ciao : Rocco

Un modulo è caricato solo una volta, a prescindere dal numero di volte che è importato. Questo previene l’esecuzione multipla di un modulo se importato più e più volte.

L’istruzione fromimport

L’istruzione from di python permette di importare specifici attributi da un modulo nel namespace corrente. La sintassi è la seguente:

from module import nome1[, nome2[, ... nomeN]]

Ad esempio se vogliamo importare solamente la funzione di Fibonacci dal modulo python fib, è sufficiente eseguire:

from fib import fibonacci

L’istruzione non importa l’intero modulo fib.

L’istruzione fromimport *

E’ possibile importare tutti gli oggetti all’interno di un modulo all’interno del namespace corrente con la seguente istruzione di import:

from module import *

Dove * sta a indicare ‘tutto’. Quest’istruzione dev’essere utilizzata con moderazione.

Localizzare i moduli

Quando si importa un modulo, l’interprete Python cerca il modulo seguendo questa sequenza:

– Directory corrente.
– Se il modulo non è trovato nella directory corrente, python cerca nel percorso PYTHONPATH (variabile globale di sistema).
– Se ancora il modulo non viene trovato, Python cerca del percorso di default, su UNIX solitamente è: usr/local/lib/python

I percorsi di ricerca sono memorizzati nel modulo di sistema sys nella variabile path, quindi in sys.path troviamo la directory corrente, PYTHONPATH, e il percorso d’installazione di python di default.

La variabile PYTHONPATH

PYTHONPATH come già detto è una variabile d’ambiente.
In un sistema Windows, con Python 3.4 installato è solitamente:

set PYTHONPATH=C:\Python34\lib;

mentre in un sistema UNIX:

set PYTHONPATH=/usr/local/lib/python

Namespaces e Scope

Le variabili sono nomi (identificatori) mappati ad un oggetto. Un namespace è un dizionario con nomi di variabili (chiavi) e i loro oggetti corrispondenti (valori).

Un’istruzione Python può accedere a variabili in namespace locali e namespace globali. Se una variabile locale e globale hanno lo stesso nome, la variabile locale nasconde la variabile globale.

Ogni funzione ha il proprio namespace locale. E così per i metodi di classe, che seguono le stesse regole delle funzioni.

Python ha protocolli rigidi ben affermati. Assume che ogni variabile a cui si assegna un valore in una funzione è locale.
Quindi, volendo assegnare un valore ad una variabile globale dall’interno di una funzione bisogna assicurarsi d’aver usato l’istruzione global.

L’istruzione global nome_variabile dice a Python che nome_variabile è una variabile globale. Quindi non andrà a cercarla nel namespace locale, bensì in quello globale.

Ecco un esempio:

Denaro = 1000
 
def aggiungiDenaro():
   # Decommenta la linea seguente per sistemare il codice:
   # global Denaro
   Denaro = Denaro + 1
 
print(Denaro)
aggiungiDenaro()
print(Denaro)

Eseguendolo ci si rende facilmente conto della necessità dell’istruzione global.

La funzione dir()

La funzione dir() restituisce una lista ordinata di stringhe con moduli, attributi, variabili e funzioni definiti all’interno di un modulo.

Per esempio:

import math
 
x = dir(math)
 
print(x)

L’output dello script sarà:

['__doc__', '__file__', '__name__', 'acos', 'asin', 'atan', 
'atan2', 'ceil', 'cos', 'cosh', 'degrees', 'e', 'exp', 
'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 
'sqrt', 'tan', 'tanh']

In particolare le variabili speciali son quelle circondate dagli underscore. La variabile speciale __name__ conterrà il nome del modulo, mentre __file__ conterrà il nome del file da cui è stato caricato il modulo.

Le funzioni globals() e locals()

Le funzioni globals() e locals() possono essere usate per restituire gli attributi dei namespace locali e globali a seconda della locazione dal quale sono stati chiamati.

Se locals() viene chiamato all’interno di una funzione, restituirà tutti gli attributi che possono essere acceduti localmente da quella funzione.

Se globals() viene chiamato all’interno di una funzione, restituirà tutti gli attributi che possono essere acceduti globalmente da quella funzione.

Il tipo di dato restituito da entrambe le funzioni è un dizionario. Quindi si possono estrarre facilmente usando la funzione keys().

La funzione reload()

Quando il modulo è importato all’interno di uno script, il codice viene eseguito solo una volta.

Di conseguenza, se voleste rieseguire il codice in un modulo, potete usare la funzione reload(). La funzione reload infatti importa nuovamente un modulo già importato in precedenza. Questa è la sintassi:

reload(nome_modulo)

I Packages in Python

Un package è una struttura gerarchia di directory che definisce un singolo ambiente applicativo per Python, che può contenere moduli, sub-packages e così via.
Consideriamo un file A.py disponibile nella directory Prova. Questo file è così definito:

def A():
   print("Sono A")

In modo simile, consideriamo altri due file che abbiano una funzione uguale al nome del file:
– Prova/B.py con una funzione B().
– Prova/C.py con una funzione C().

Ora, creiamo un altro file chiamato __init__.py nella directory ‘Prova’:
– Prova/__init__.py

Ora per rendere disponibili tutte le funzioni quando importate ‘Prova’, dovete inserire alcune istruzioni esplicite di import all’interno di __init__.py come segue:

from Prova import A
from Prova import B
from Prova import C

Dopo aver aggiunto queste linee all’interno di __init__.py, avrete tutte queste funzioni disponibili quando importerete il package ‘Prova’.

#Importiamo il package
import Prova
 
Prova.A()
Prova.B()
Prova.C()

Quando il codice sopra viene eseguito, il risultato prodotto sarà:

Sono A
Sono B
Sono C

Nell’esempio sopra abbiamo preso d’esempio una singola funzione all’interno di ogni file, ma è possibile inserire un numero arbitrario di funzioni in ogni file. E’ possibile definire anche differenti classi in Python in questi file e creare un Package che le comprenda tutte.

Per qualsiasi dubbio o chiarimento commentate e non dimenticare di condividere!