8.4. Rivisitazione della mappatura delle liste

Siete già abituati ad usare la list comprehensions per mappare una lista in un altra. C'è un altro modo per fare la stessa cosa, usando la funzione built-in map. Funziona in modo molto simile alla funzione filter.

Esempio 8.10. Introducendo map

>>> def double(n):
...     return n*2
...     
>>> li = [1, 2, 3, 5, 9, 10, 256, -3]
>>> map(double, li)                       1
[2, 4, 6, 10, 18, 20, 512, -6]
>>> [double(n) for n in li]               2
[2, 4, 6, 10, 18, 20, 512, -6]
>>> newlist = []
>>> for n in li:                          3
...     newlist.append(double(n))
...     
>>> newlist
[2, 4, 6, 10, 18, 20, 512, -6]
1 map richiede una funzione ed una lista [15] e restituisce una nuova lista chiamando la funzione ed ordinandola per ogni elemento della lista. In questo caso la funzione moltiplica semplicemente ogni elemento per 2.
2 Potreste arrivare allo stesso risultato con una list comprehension. La list comprehension è stata introdotta in Python 2.0; map esiste da sempre.
3 Potreste, se insistete a pensare come un programmatore di Visual Basic, usare un ciclo for per fare lo stesso lavoro.

Esempio 8.11. map con liste di tipi di dato diversi

>>> li = [5, 'a', (2, 'b')]
>>> map(double, li)                       1
[10, 'aa', (2, 'b', 2, 'b')]
1 Come nota a margine, preferisco sottolineare che map funziona bene anche con liste di tipi di dato diversi, almeno finché la funzione che state usando gestisce bene i vari tipi di dato. In questo caso, la nostra funzione double moltiplica semplicemente l'argomento ricevuto per 2, Python fa La Cosa Giusta a seconda del tipo di dato dell'argomento. Per gli interi, significa proprio moltiplicare per 2; per le stringhe, significa concatenare la stringa con se stessa; per le tuple, significa creare una nuova tupla che ha tutti gli elementi dell'originale e ancora, a seguire, un suo duplicato.

Bene, abbiamo giocato abbastanza. Diamo un'occhiata ad un po' di codice vero.

Esempio 8.12. map in regression.py

    filenameToModuleName = lambda f: os.path.splitext(f)[0] 1
    moduleNames = map(filenameToModuleName, files)          2
1 Come abbiamo visto nella sezione Usare le funzioni lambda, lambda definisce una funzione inline. Come abbiamo visto nell'Esempio 4.36, “Dividere i pathnames”, os.path.splitext riceve come parametro un nome di file e restituisce una tupla (nome, estensione). Quindi filenameToModuleName è una funzione che riceverà un nome di file, toglierà l'estensione e ne restituirà solamente il nome.
2 Chiama map per ogni nome di file elencato in files, passa il nome-file alla nostra funzione filenameToModuleName e restituisce una lista di valori risultante da ogni chiamata della funzione. In altre parole, eliminiamo l'estensione di ogni nome di file e conserviamo la lista di tutte queste parti di nomi in moduleNames.

Come vedremo nel resto del capitolo, possiamo estendere questo atteggiamento di pensiero data-centrico adattandolo al nostro scopo, che in definitiva è eseguire un singolo test che contenga tutti quei singoli test che ci servono.

Footnotes

[15] Ancora, devo sottolineare che map può ricevere una lista, una tupla, o un qualsiasi oggetto simile ad una sequenza. Controllate la nota precedente riguardo a filter.