5: FORMATTAZIONE DI STRINGHE

PROBLEMI DI FORMATTAZIONE

Scriviamo in IDLE un semplice ciclo che stampa i quadrati e i cubi dei numeri da 1 a 10 (dopo aver scritto la seconda riga dovete premere due volte <INVIO> per eseguirlo):


>>> for i in range(1, 11):
        print(i, i ** 2, i ** 3)
		

1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000

L'output di IDLE è abbastanza sgraziato: man mano che i numeri diventano più grandi occupano sempre più spazi, e così non sono incolonnati. Si potrebbe senz'altro cercare di allineare questi numeri con delle istruzioni supplementari, ma ciò ci porterebbe a parecchie complicazioni.

NUOVO PROGRAMMA: venditori.py

Ecco un altro esempio: qui abbiamo una lista di venditori, ognuno dei quali ha ottenuto un certo numero di vendite e ha diritto ad una provvigione (un venditore è memorizzato in un vocabolario con nome, cognome, vendite e percentuale della provvigione). Vogliamo stampare un elenco dei venditori con l'ammontare della provvigione spettante ad ognuno di essi. Copiate nell'editor di testo questo programma:


venditori = [
    { "cognome":"Abbotti", "nome":"Giovanni", "vendite":36515.35, "provvigione":2.35 },
    { "cognome":"Bellini", "nome":"Luigi", "vendite":45210.00, "provvigione":2.5 },
    { "cognome":"Cardellini", "nome":"Matteo", "vendite":28534.50, "provvigione":3.12 },
    { "cognome":"Decini", "nome":"Piervittorio", "vendite":33782.80, "provvigione":2.94 }
]

for v in venditori:
    print(v["cognome"], v["nome"], v["vendite"] * v["provvigione"] / 100)

Se lo eseguite otterrete questo output:


Abbotti Giovanni 858.110725
Bellini Luigi 1130.25
Cardellini Matteo 890.2764
Decini Piervittorio 993.21432

Anche qui l'effetto grafico è orribile: nomi, cognomi e numeri dovrebbero essere stampati su tre colonne diverse; i numeri, poi, dovrebbero essere allineati alla virgola e tutti con due decimali. Anche questo si potrebbe fare con delle istruzioni supplementari, ma alla fine impiegheremmo probabilmente più tempo per ottenere un output corretto che per risolvere il problema di calcolare le provvigioni!

FORMATTARE LE STRINGHE

Tutti i linguaggi di programmazione (alcuni dei quali risalgono ai tempi in cui l'unico output possibile era la stampa su carta) offrono delle istruzioni per controllare approfonditamente quello che si stampa (allineamento di numeri e parole, numero di decimali, ecc.). La comodità della funzione print() di Python fa sì che, il più delle volte, sia sufficiente usarla nella sua forma più semplice, ma se vogliamo un maggiore controllo anche Python ci offre parecchi strumenti.

Va detto che nel corso degli anni e delle varie versioni Python ha avuto un evoluzione: fino a Python 2 veniva adottata una serie di istruzioni che richiamavano quelle usate nel linguaggio C, dalla versione 3 sono state invece introdotte delle nuove istruzioni totalmente differenti, che danno maggiori possibilità di controllo. Oggi ci si riferisce ai due sistemi come "Old style formatting" e "New style formatting". L'old style è ancora accettato da Python 3 ma i nuovi utenti sono incoraggiati ad usare il new style. Per questa ragione parleremo qui solo di quest'ultimo, ed anche così dovremo limitarci solo alle caratteristiche più usate, perchè le varie combinazioni di possibilità sono veramente moltissime e costituiscono un vero e proprio "mini linguaggio" all'interno di Python. Del resto, chi avesse già dimestichezza con il C non dovrebbe avere troppi problemi ad imparare le istruzioni old style.

IL METODO FORMAT

La base della formattazione "new style" in Python è il metodo format(), che si può applicare ad una stringa con la solita sintassi con il punto. Apriamo IDLE e scriviamo:


>>> "Ciao mamma!".format()

'Ciao mamma!'

>>> s = "Ciao Luigi!"
>>> s.format()

'Ciao Luigi!'

Notate che abbiamo applicato il metodo prima ad una costante (cioè una stringa scritta esplicitamente tra virgolette) e poi ad una variabile contenente una stringa. IDLE come al solito risponde stampando il valore restituito dal metodo, cioè, per il momento, la stringa immutata. Vedremo adesso come manipolare per mezzo del format() quello che vogliamo stampare.

Il format() interviene sulla stringa alla quale è applicato modificandola in vari modi. Per consentirgli di fare ciò dobbiamo per prima cosa indicargli le parti della stringa che deve modificare tramite dei campi di sostituzione (nella documentazione ufficiale replacement fields, nel seguito li chiameremo solo campi), seguendo queste regole:

Ecco subito un esempio per capire meglio:


>>> s = "Ciao {}!"            # stringa che contiene un campo di sostituzione
>>> s.format("Luigi")         # sostituisce "Luigi" al posto del campo

'Ciao Luigi!'

>>> s.format("Sandra")        # sostituisce "Sandra"

'Ciao Sandra'

>>> a = 10
>>> b = 20
>>> "{} x {} = {}".format(a, b, a * b) # tre campi, tre parametri

'10 x 20 = 200'

>>> "{{{}}}".format(a)       # come scrivere le parentesi graffe

'{10}'

Nella prima istruzione abbiamo definito una stringa s contenente un campo di sostituzione (le due parentesi graffe). Nella seconda e terza abbiamo usato il format()per sostituire al posto delle parentesi prima "Luigi" e poi "Sandra". Osserviamo ora le altre istruzioni: prima assegniamo un valore a due variabili a e b, poi le stampiamo (con il loro prodotto) usando un format(). Infine, nell'ultima istruzione, stampiamo una variabile tra parentesi graffe: dobbiamo usarne tre di seguito (due per la parentesi ed una per il campo).

Scrivendo le parentesi aperte e subito chiuse i parametri del format() verranno assegnati ai campi secondo il loro ordine, ma possiamo anche aggirare questa regola indicando noi la corrispondenza tra campi e parametri. Anche qui abbiamo diverse opzioni (ve l'ho detto, si tratta di un vero e proprio mini-linguaggio, se vi sembra troppo complicato potete anche saltare questa parte e riprenderla quando avrete le idee più chiare).

A questo punto, probabilmente, molti di voi staranno pensando: ma fino ad ora non c'è niente di nuovo! Abbiamo solo imparato un modo più complicato di fare cose che già sapevamo fare! E' vero, ma da ora cominciamo a vedere altre regole che ci permettono di modficare più radicalmente la stringa a cui è applicato il format(). All'interno di un campo di sostituzione possiamo inserire altri caratteri specificatori di formato che controllano la larghezza della stampa, l'allineamento ecc.

FORMATTARE IL TESTO

Cominciamo dalla formattazione del testo: gli specificatori di formato devono cominciare con un carattere due punti ':' e devono seguire questa sintassi (un nome racchiuso tra parentesi quadre indica che esso è opzionale):

:[carattere di riempimento][carattere di allineamento][larghezza del campo][.troncamento]

Cerchiamo subito di capire meglio con qualche esempio:


>>> "{:>20}".format("Luigi")        # larghezza 20, allineato a destra

'               Luigi'

>>> "{:<20}".format("Luigi")        # larghezza 20, allineato a sinistra

'Luigi               '

>>> "{:20}".format("Luigi")         # il testo e' allineato a sinistra di default

'Luigi               '

>>> "{:_^20}".format("Luigi")       # centrato e con carattere di riempimento

'_______Luigi________'

>>> "{:20}".format("Precipitevolissimevolmente")      # stringa lunga senza troncamento

'Precipitevolissimevolmente'

>>> "{:20.20}".format("Precipitevolissimevolmente")   # stringa lunga con troncamento

'Precipitevolissimevo'

>>> # keyword arguments (vanno PRIMA dei due punti)
>>> "{nome:>15}{cognome:>15}".format(nome="Luigi", cognome="Rossi")

'          Luigi          Rossi'

Ricordate di seguire esattamente l'ordine indicato, altrimenti otterrete un errore:


>>> "{:10>}".format("Luigi")    # il > va PRIMA del 10

Traceback (most recent call last):
  File "", line 1, in 
    "{:10>}".format("Luigi")
ValueError: Unknown format code '>' for object of type 'str'

Queste regole ci permettono già di migliorare notevolmente il nostro programma venditori.py. Modificate le ultime righe in questo modo:


    .   .   .

for v in venditori:
    s = "{:15} {:15} {}".format(v["cognome"], v["nome"], v["vendite"] * \
                                 v["provvigione"] / 100)
    print(s)

che ci faranno ottenere finalmente i nomi dei venditori incolonnati:


Abbotti         Giovanni        858.110725
Bellini         Luigi           1130.25
Cardellini      Matteo          890.2764
Decini          Piervittorio    993.21432
ESERCIZIO 3.1 Variate la riga che definisce la stringa s: allineate i nomi a destra o al centro, usate l'asterisco "*" come carattere di riempimento, variate la larghezza dei campi
ESERCIZIO 3.2 Cercate ora di ottenere questo formato:

Abbotti         G.   858.110725
Bellini         L.   1130.25
Cardellini      M.   890.2764
Decini          P.   993.21432
  
SUGGERIMENTO: dovete stampare solo la prima lettera del nome ... il punto dopo l'iniziale va invece inserito nella stringa a cui viene applicato il format, dopo il campo di sostituzione. Lasciate tre spazi tra l'iniziale e l'importo delle vendite

FORMATTARE I NUMERI

Per la formattazione dei numeri le cose si complicano un po', in quanto Python ci mette a disposizione moltissime opzioni: possiamo controllare il numero di decimali, la base (decimale, binaria, esadecimale ...), la notazione esponenziale ...; nel seguito cercherò di essere il più completo possibile, ma va da sè che probabilmente non avrete mai bisogno di tutte queste opzioni, e quindi vi basta capire gli esempi principali; se in futuro avrete bisogno di stampare numeri in forma esadecimale vi basterà cercare il codice specifico in qualche reference. Ecco il formato completo degli specificatori:

:[[riempimento]allineamento][segno][#][0][larghezza][,][.precisione][tipo]

Di nuovo, lo specificatore deve cominciare con i due punti, seguiti (nell'ordine preciso in cui sono indicati) dai vari blocchi, tutti opzionali. Analizziamoli uno per uno (per maggiore chiarezza non li elencherò nello stesso ordine in cui si presentano):

Finito lungo questo elenco di opzioni potete provare a fare qualche esercizio:

ESERCIZIO 4.2 Copiate in IDLE la seguente istruzione (che stampa 25)
>>> "{:}".format(25)
Ora cambiate lo specificatore tra parentesi graffe, in modo da ottenere questi output (ricordate sempre, se dovete applicare più modificatori, di seguire esattamente l'ordine del modello dato, o otterrete degli errori):
'0025'
'+0025'
'**+25'
'+**25'
'25.00'
'+2.50e01'
'+ 2.50E01' (uno spazio prima del numero)
'   11001'  (tre spazi prima del numero)
'11001   '  (tre spazi dopo)
'0x19'
ESERCIZIO 4.3 Riprendete il nostro esempio iniziale:

>>> for i in range(1, 11):
        print(i, i ** 2, i ** 3)
e cambiate l'istruzione print() in modo da avere questo output:
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000
SUGGERIMENTO: dovete sostituire i tre argomenti della print() con un solo argomento: una stringa che contiene tre campi di sostituzione formattati con il format(). Notate l'ultima riga: c'è un solo spazio tra 10 100 1000
ESERCIZIO 4.3 Finalmente possiamo allineare anche i numeri nel nostro programma venditori.py: modificatelo in modo da ottenere questo output:

Abbotti         Giovanni         858.11
Bellini         Luigi           1130.25
Cardellini      Matteo           890.28
Decini          Piervittorio     993.21

Fine della lezione