Storia della domanda
La funzione map() proviene dalla programmazione funzionale (fin dagli albori di Lisp), ed è progettata per applicare una funzione a ogni elemento di una sequenza restituendo un nuovo oggetto iterable con i risultati. In Python è stata introdotta molto prima dell'arrivo delle espressioni generatore e delle espressioni di lista, ma continua ad essere ampiamente utilizzata, specialmente in grandi pipeline di elaborazione dati.
Problema
Se è necessario modificare ogni elemento di una collezione secondo una certa regola, le soluzioni basate sui cicli for tendono a diventare ingombranti e meno leggibili. Le espressioni di lista e map() consentono di esprimere l'intento in modo compatto. È importante comprendere le differenze tra questi approcci per scegliere lo strumento giusto.
Soluzione
map(func, iterable) crea un iteratore pigro, in cui gli elementi della sequenza originale sono trasformati dalla funzione funcmap non calcola gli elementi immediatamente, ma lavora in modo pigrodef square(x): return x * x squares = map(square, [1, 2, 3]) print(list(squares)) # [1, 4, 9]
L'espressione di lista [square(x) for x in [1, 2, 3]] fa lo stesso, ma restituisce immediatamente una lista, mentre l'espressione generatore (square(x) for x in [1, 2, 3]) è un generatore pigro.
Caratteristiche chiave:
Restituisce map() una lista in Python 3?
No, a partire da Python 3, map() non restituisce una lista, ma un iteratore pigro. Per ottenere una lista, è necessario racchiudere manualmente il risultato in list().
res = map(str.upper, ['a', 'b']) print(res) # <map object ...> print(list(res)) # ['A', 'B']
È possibile utilizzare map() per aggiungere una condizione di filtraggio all'interno della funzione?
No, map() non filtra gli elementi, ma li trasforma. Per il filtraggio usa filter() o un'espressione di lista:
result = map(str.upper, ['a', 'b', None]) # Se arriva None, map solleverà un errore chiamando str.upper(None) # filter aiuterà a rimuovere None prima di map
È possibile utilizzare map() per scorrere contemporaneamente due sequenze?
Sì, map() può accettare un numero qualsiasi di sequenze e la funzione di trasformazione deve accettare lo stesso numero di argomenti:
x = [1, 2, 3] y = [10, 20, 30] result = map(lambda a, b: a + b, x, y) print(list(result)) # [11, 22, 33]
Il programmatore si aspetta di ottenere una lista immediatamente:
mapped = map(abs, [-1, -2, -3]) print(mapped[1]) # TypeError: 'map' object is not subscriptable
Vantaggi:
Svantaggi:
Utilizzo di un'espressione generatore per il filtraggio e map() per la trasformazione:
nums = range(-5, 6) positives = (x for x in nums if x > 0) sq = map(lambda n: n * n, positives) print(list(sq)) # [1, 4, 9, 16, 25, 36]
Vantaggi:
Svantaggi: