3.8. Unire il tutto

L'ultima riga di codice, l'unica che ancora non abbiamo analizzato, è quella che svolge l'intero lavoro. Ma adesso il lavoro è semplice, perché ogni cosa di cui abbiamo bisogno è già impostata come serve a noi. Tutte le tessere sono al loro posto; è ora di buttarle giù.

Esempio 3.25. Il succo di apihelper.py

    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])

Notate che questo è un solo comando, suddiviso su più righe e non usa il carattere di continuazione (“\”). Ricordate quando dicevo che alcune espressioni possono essere suddivise in più righe senza usare un backslash? La list comprehension è una di queste, in quanto l'intera espressione è contenuta tra parentesi quadre.

Adesso cominciamo dalla fine e lavoriamo all'indietro. Il


for method in methodList

ci mostra che questa è una list comprehension. Come sappiamo, methodList è una lista di tutti i metodi di object ai quali siamo interessati. Quindi stiamo eseguendo un ciclo lungo questa lista con un certo metodo.

Esempio 3.26. Ottenere dinamicamente una docstring

>>> import odbchelper
>>> object = odbchelper                   1
>>> method = 'buildConnectionString'      2
>>> getattr(object, method)               3
<function buildConnectionString at 010D6D74>
>>> print getattr(object, method).__doc__ 4
Build a connection string from a dictionary of parameters.

    Returns string.
1 Nella funzione help, object è l'oggetto dal quale stiamo ottenendo l'aiuto, passato come argomento.
2 Siccome stiamo eseguendo un ciclo attraverso methodList, method è il nome del metodo corrente.
3 Usando la funzione getattr, stiamo ottenendo un riferimento alla funzione method nel modulo object.
4 Adesso stampare l'attuale docstring del metodo è semplice.

Il prossimo pezzo del puzzle è l'utilizzo di str sulla stringa di documentazione. Come forse ricorderete, str è una funzione built-in che forza i dati in una stringa. Ma una stringa di documentazione è sempre una stringa dunque perché preoccuparsi di usare la funzione str? La risposta è che non tutte le funzioni hanno una stringa di documentazione e se non ce l'hanno, il loro attributo __doc__ vale None.

Esempio 3.27. Perchè usare str su una stringa di documentazione?

>>> >>> def foo(): print 2
>>> >>> foo()
2
>>> >>> foo.__doc__     1
>>> foo.__doc__ == None 2
1
>>> str(foo.__doc__)    3
'None'
1 Possiamo facilmente definire una funzione che non ha una docstring, quindi il suo attributo __doc__ vale None. Per fare ancora più confusione, se valutate l'attributo __doc__ direttamente, la IDE di Python non stampa nulla, che ha senso se ci pensate, ma non è di grande aiuto.
2 Potete verificare che il valore dell'attributo __doc__ è None confrontandolo direttamente.
3 Quando la funzione str prende in ingresso un valore nullo, ne ritorna la sua rappresentazione in forma di stringa, 'None'.
Nota
In SQL, dovete usare IS NULL invece di = NULL per confrontare un valore nullo. In Python, potete usare indifferentemente == None o is None, ma is None è più efficiente.

Adesso che ci siamo garantiti di avere una stringa, possiamo passare la stringa a processFunc, che abbiamo già definito come una funzione che comprime o meno gli spazi. Ora vedrete perché è stato importante usare str per convertire un valore None in una rappresentazione in stringa. processFunc assume di ricevere un argomento di tipo stringa e chiamare il suo metodo split, che restituirebbe un errore se passassimo None, perché None non ha un metodo split.

Facendo un ulteriore passo indietro, possiamo notare che stiamo usando nuovamente la formattazione delle stringhe per concatenare il valore di ritorno di processFunc con il valore di ritorno del metodo ljust. Questo è un nuovo metodo delle stringhe che non abbiamo visto prima.

Esempio 3.28. Introduzione al metodo ljust

>>> s = 'buildConnectionString'
>>> s.ljust(30) 1
'buildConnectionString         '
>>> s.ljust(20) 2
'buildConnectionString'
1 ljust riempie la stringa con spazi bianchi fino ad arrivare al valore assegnato alla lunghezza. È ciò che la funzione help usa per creare due colonne di output ed allineare tutte le stringhe di documentazione nella seconda colonna.
2 Se il valore assegnato alla lunghezza è più piccolo dell'attuale lunghezza della stringa, ljust semplicemente ritornerà la stringa senza alcuna modifica. Non tronca mai una stringa.

Abbiamo quasi finito. Dato il nome incolonnato dal metodo ljust e la (possibilmente priva di spazi bianchi) docstring della chiamata a processFunc, concateniamo i due ed otteniamo una singola stringa. Siccome stiamo mappando methodList, arriveremo ad ottenere una lista di stringhe. Usando il metodo join sulla stringa "\n", concateniamo questa lista in una singola stringa, con ogni elemento della lista su una riga a se stante e stampiamo il risultato.

Esempio 3.29. Stampare una lista

>>> li = ['a', 'b', 'c']
>>> print "\n".join(li) 1
a
b
c
1 Si tratta inoltre di un utile trucco per il debugging quando state lavorando con le liste. Ed in Python, lavorerete continuamente con le liste.

Questo è l'ultimo pezzo del puzzle. Ora il codice dovrebbe essere chiaro.

Esempio 3.30. Il succo di apihelper.py, rivisitato

    print "\n".join(["%s %s" %
                      (method.ljust(spacing),
                       processFunc(str(getattr(object, method).__doc__)))
                     for method in methodList])