4.13. Ancora sui moduli

I moduli, come qualunque altra cosa in Python, sono oggetti. Una volta importato, si può sempre ottenere un riferimento ad un modulo attraverso il dizionario globale sys.modules.

Esempio 4.31. Introduzione a sys.modules

>>> import sys                          1
>>> print '\n'.join(sys.modules.keys()) 2
win32api
os.path
os
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
1 Il modulo sys contiene informazioni a livello di sistema, quali la versione di Python che si sta usando (sys.version oppure sys.version_info), nonché opzioni di sistema come la massima profondità di ricorsione permessa (sys.getrecursionlimit() e sys.setrecursionlimit()).
2 sys.modules è un dizionario contenente tutti i moduli che sono stati importati sin dalla partenza di Python, la chiave è il nome del modulo, il valore è l'oggetto-modulo. Si noti che questo dizionario non comprende solo i moduli importati esplicitamente dal vostro programma. Python carica alcuni moduli alla partenza; se poi si sta usando la IDE di Python, sys.modules contiene tutti i moduli importati da tutti i programmi che sono stati lanciati tramite l'IDE.

Esempio 4.32. Usare sys.modules

>>> import fileinfo         1
>>> print '\n'.join(sys.modules.keys())
win32api
os.path
os
fileinfo
exceptions
__main__
ntpath
nt
sys
__builtin__
site
signal
UserDict
stat
>>> fileinfo
<module 'fileinfo' from 'fileinfo.pyc'>
>>> sys.modules["fileinfo"] 2
<module 'fileinfo' from 'fileinfo.pyc'>
1 Quando vengono importati nuovi moduli, questi vengono aggiunti al dizionario sys.modules. Questo spiega perché importare la seconda volta lo stesso modulo è molto veloce: Python lo ha già caricato e memorizzato nel modulo sys.modules, per cui importarlo la seconda volta corrisponde semplicemente ad una ricerca nel dizionario.
2 Dato il nome (come stringa) di ogni modulo precedentemente importato, è possibile ottenere un riferimento al modulo stesso attraverso il dizionario sys.modules.

Esempio 4.33. L'attributo di classe __module__

>>> from fileinfo import MP3FileInfo
>>> MP3FileInfo.__module__              1
'fileinfo'
>>> sys.modules[MP3FileInfo.__module__] 2
<module 'fileinfo' from 'fileinfo.pyc'>
1 Ogni classe Python ha un attributo di classe predefinito di nome __module__, che contiene il modulo in cui la classe è definita.
2 Combinando questo, con il diziorario sys.modules, si può ottenere un riferimento al modulo in cui una classe è definita.

Esempio 4.34. Uso di sys.modules in fileinfo.py

    def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]):       1
        "get file info class from filename extension"                             
        subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:]        2
        return hasattr(module, subclass) and getattr(module, subclass) or FileInfo 3
1 Questa è una funzione con due argomenti: il nome del file è richiesto, ma il parametro module è opzionale ed ha come predefinito il modulo che contiene la classe FileInfo. Questo sembra inefficiente, perché si potrebbe credere che Python calcoli l'espressione con sys.modules ogni volta che la funzione è invocata. In realtà, Python calcola l'espressione usata come valore predefinito solo una volta, la prima volta che il modulo viene importato. Come si vedrà più avanti, questa funzione non viene mai chiamata con l'argomento module, cosicché module è usato come una costante definita a livello di funzione.
2 Scaveremo su questa traccia più avanti, dopo che ci saremo immersi nell'analisi del modulo os. Per ora fidatevi, la variabile subclass finisce per avere come valore il nome di una classe, come MP3FileInfo.
3 Si sa già tutto su getattr, che permette di ottenere il riferimento ad un oggetto dal suo nome. hasattr è una funzione complementare che controlla se un oggetto ha un particolare attributo; in questo caso, se un modulo ha una classe particolare (sebbene funzioni per ogni oggetto ed ogni attributo, proprio come getattr). In Italiano, questa linea di codice recita: “se questo modulo contiene una classe con lo stesso nome di subclass allora restituisci tale classe, altrimenti restituisci la classe base FileInfo”.

Ulteriori letture