8.7. Mettere assieme il tutto (parte 1)

Ora abbiamo imparato abbastanza da poter scomporre le prime sette linee dell'esempio di questo capitolo: leggere una directory ed importare alcuni dei moduli che vi sono contenuti.

Esempio 8.16. La funzione regressionTest, parte 1


def regressionTest():
    path = os.path.abspath(os.path.dirname(sys.argv[0]))   
    files = os.listdir(path)                               
    test = re.compile("test\.py$", re.IGNORECASE)          
    files = filter(test.search, files)                     
    filenameToModuleName = lambda f: os.path.splitext(f)[0]
    moduleNames = map(filenameToModuleName, files)         
    modules = map(__import__, moduleNames)                 

Osserviamolo linea per linea, interattivamente. Assumendo che la directory corrente sia c:\diveintopython\py, che contiene gli esempi di questo libro, compreso lo script di questo capitolo. Come abbiamo visto in Trovare il percorso, la directory degli script sarà contenuta nella variabile path, per cui ne assegnamo il valore e procediamo.

Esempio 8.17. Passo 1: Leggere i nomi dei file

>>> import sys, os, re, unittest
>>> path = r'c:\diveintopython\py'
>>> files = os.listdir(path)                               
>>> files 1
['BaseHTMLProcessor.py', 'LICENSE.txt', 'apihelper.py', 'apihelpertest.py',
'argecho.py', 'autosize.py', 'builddialectexamples.py', 'dialect.py',
'fileinfo.py', 'fullpath.py', 'kgptest.py', 'makerealworddoc.py',
'odbchelper.py', 'odbchelpertest.py', 'parsephone.py', 'piglatin.py',
'plural.py', 'pyfontify.py', 'regression.py', 'roman.py', 'romantest.py',
'uncurly.py', 'unicode2koi8r.py', 'urllister.py', 'kgp', 'roman',
'colorize.py']
1 files è una lista di tutti i file e le directory nella directory degli script. (Se avete già eseguito alcuni degli esempi, potrete anche notare, tra gli altri, anche qualche file .pyc.)

Esempio 8.18. Passo 2: Filtrare per trovare i file necessari

>>> test = re.compile("test\.py$", re.IGNORECASE)           1
>>> files = filter(test.search, files)                      2
>>> files                                                   3
['apihelpertest.py', 'kgptest.py', 'odbchelpertest.py', 'romantest.py']
1 Questa espressione regolare corrisponderà ad ogni stringa che termina con test.py. È importante notare che è necessario far precedere il punto dal carattere escape ("\"), visto che un punto, all'interno di una espressione regolare, normalmente significa “corrisponde ad ogni singolo carattere”.
2 L'espressione regolare compilata agisce come una funzione, così può essere usata per filtrare la grande lista di file e directory, per trovare quelli che corrispondono all'espressione regolare.
3 In questo modo è rimasta solo la lista degli script di test, poiché questi sono i soli con nomi del tipo QUALCOSAtest.py.

Esempio 8.19. Passo 3:Trasformare i nomi dei file in nomi di moduli

>>> filenameToModuleName = lambda f: os.path.splitext(f)[0] 1
>>> filenameToModuleName('romantest.py')                    2
'romantest'
>>> filenameToModuleName('odchelpertest.py')
'odbchelpertest'
>>> moduleNames = map(filenameToModuleName, files)          3
>>> moduleNames                                             4
['apihelpertest', 'kgptest', 'odbchelpertest', 'romantest']
1 Come si è visto in Usare le funzioni lambda, lambda è un modo veloce, anche se poco elegante, per creare delle semplici funzioni su una sola riga. Questa accetta come argomento un nome di file con estensione e restituisce solo il nome vero e proprio, grazie all'uso della funzione standard di libreria os.path.splitext vista nell'Esempio 4.36, “Dividere i pathnames”.
2 filenameToModuleName è una funzione. Non c'è niente di magico nelle funzioni lambda rispetto alle normali funzioni definite con l'istruzione def. filenameToModuleName può essere chiamata come ogni altra funzione e fa esattamente ciò che si desiderava: rimuove l'estensione dal suo argomento.
3 Ora la funzione può essere applicata ad ogni file della lista dei file di test delle unità, utilizzando map.
4 Il risultato è proprio quello cercato: una lista di moduli, sotto forma di stringhe.

Esempio 8.20. Passo 4: Trasformare i nomi di moduli in moduli

>>> modules = map(__import__, moduleNames)                  1
>>> modules                                                 2
[<module 'apihelpertest' from 'apihelpertest.py'>,
<module 'kgptest' from 'kgptest.py'>,
<module 'odbchelpertest' from 'odbchelpertest.py'>,
<module 'romantest' from 'romantest.py'>]
>>> modules[-1]                                             3
<module 'romantest' from 'romantest.py'>
1 Come si è visto in Importare dinamicamente i moduli, si possono utilizzare map ed __import__ insieme per trasformare una lista di nomi di moduli (sotto forma di stringhe) in veri moduli (ai quali si può accedere come ad ogni altro modulo).
2 modules è una lista di moduli, alla quale si può accedere come ad ogni altro modulo.
3 L'ultimo modulo nella lista è il modulo romantest, proprio come se si fosse utilizzato import romantest. Come si vedrà nella sezione successiva, non solo si può accedere a questo modulo, istanziare le classi contenute in esso e chiamarne le funzioni, si può fare introspezione nel modulo per scoprire quali classi e funzioni contiene.