Table of Contents
Introduction
La fonction map() est l’une des pierres angulaires de la programmation fonctionnelle en Python. Elle incarne parfaitement le principe de transformation de donnees sans effets de bord, permettant d’appliquer une fonction a chaque element d’un ou plusieurs iterables de maniere elegante et concise.
Pourquoi maitriser map() est essentiel ?
Dans le developpement Python moderne, map() offre plusieurs avantages majeurs :
- Lisibilite : Le code exprime clairement l’intention de transformer des donnees
- Performance :
map()est implemente en C dans CPython, offrant des performances superieures aux boucles Python classiques - Lazy evaluation : En Python 3.x,
map()retourne un iterateur, economisant la memoire pour les grandes collections - Composabilite : S’integre parfaitement avec d’autres fonctions comme
filter(),reduce()et les comprehensions
Dans cet article, nous allons explorer en detail la fonction map(), ses utilisations avancees, ses differences entre Python 2.x et Python 3.x, ainsi que les meilleures pratiques pour l’exploiter pleinement dans vos projets.
Section 69.1 : Utilisation de base de map(), itertools.imap et future_builtins.map
La fonction map() est la plus simple des fonctions built-in utilisees en programmation fonctionnelle. Elle applique une fonction specifique a chaque element d’un iterable.
# Syntaxe de base : map(fonction, iterable)
names = ['Fred', 'Wilma', 'Barney']
# Appliquer la fonction len() a chaque nom
result = map(len, names)
print(list(result)) # [4, 5, 6]
# Exemple avec une fonction personnalisee
def to_uppercase(s):
return s.upper()
print(list(map(to_uppercase, names))) # ['FRED', 'WILMA', 'BARNEY']
Differences Python 2.x vs Python 3.x
En Python 2.x, map() retourne directement une liste. En Python 3.x, elle retourne un objet map (iterateur), ce qui est plus efficace en memoire.
# Python 3.x - retourne un iterateur
names = ['Fred', 'Wilma', 'Barney']
result = map(len, names)
print(result) # <map object at 0x...>
print(list(result)) # [4, 5, 6]
# L'iterateur est consomme apres la premiere iteration
print(list(result)) # [] - vide car deja consomme !
Pour obtenir un comportement d’iterateur en Python 2.x, utilisez future_builtins ou itertools.imap :
# Python 2.x avec future_builtins
from future_builtins import map as fmap
print(list(fmap(len, names))) # [4, 5, 6]
# Python 2.x avec itertools.imap
from itertools import imap
print(list(imap(len, names))) # [4, 5, 6]
Section 69.2 : Mappage de chaque valeur dans un iterable
Nous pouvons utiliser map() pour appliquer une fonction a chaque element d’un iterable. Cette approche est particulierement utile pour les transformations simples.
# Utilisation avec une fonction built-in
numbers = (1, -1, 2, -2, 3, -3)
absolute_values = list(map(abs, numbers))
print(absolute_values) # [1, 1, 2, 2, 3, 3]
# Conversion de types
string_numbers = ['1', '2', '3', '4', '5']
integers = list(map(int, string_numbers))
print(integers) # [1, 2, 3, 4, 5]
# Arrondir des nombres decimaux
decimals = [1.234, 5.678, 9.012]
rounded = list(map(round, decimals))
print(rounded) # [1, 6, 9]
Utilisation avec les fonctions lambda
Les fonctions anonymes (lambda) sont frequemment utilisees avec map() pour des transformations rapides :
# Doubler chaque valeur
numbers = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, numbers))
print(doubled) # [2, 4, 6, 8, 10]
# Calculer le carre de chaque nombre
squares = list(map(lambda x: x ** 2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# Formater des chaines
names = ['alice', 'bob', 'charlie']
formatted = list(map(lambda name: name.capitalize(), names))
print(formatted) # ['Alice', 'Bob', 'Charlie']
# Extraire des donnees d'objets
users = [
{'name': 'Alice', 'age': 30},
{'name': 'Bob', 'age': 25},
{'name': 'Charlie', 'age': 35}
]
names = list(map(lambda user: user['name'], users))
print(names) # ['Alice', 'Bob', 'Charlie']
Section 69.3 : Mappage de valeurs d’iterables differents
L’une des fonctionnalites les plus puissantes de map() est sa capacite a travailler avec plusieurs iterables simultanement. La fonction est alors appelee avec un element de chaque iterable.
# Calculer la moyenne de valeurs correspondantes
def average(*args):
return float(sum(args)) / len(args)
scores_math = [100, 111, 99, 97]
scores_physics = [102, 117, 91, 102]
scores_chemistry = [104, 102, 95, 101]
averages = list(map(average, scores_math, scores_physics, scores_chemistry))
print(averages) # [102.0, 110.0, 95.0, 100.0]
Exemples pratiques avec plusieurs iterables
# Addition element par element
list1 = [1, 2, 3, 4]
list2 = [10, 20, 30, 40]
sums = list(map(lambda x, y: x + y, list1, list2))
print(sums) # [11, 22, 33, 44]
# Creer des tuples a partir de deux listes
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
people = list(map(lambda name, age: (name, age), names, ages))
print(people) # [('Alice', 25), ('Bob', 30), ('Charlie', 35)]
# Formater des donnees
prenoms = ['Jean', 'Marie', 'Pierre']
noms = ['Dupont', 'Martin', 'Durand']
full_names = list(map(lambda p, n: f"{p} {n}", prenoms, noms))
print(full_names) # ['Jean Dupont', 'Marie Martin', 'Pierre Durand']
Attention : iterables de longueurs differentes
Lorsque les iterables ont des longueurs differentes, map() s’arrete au plus court (comportement Python 3.x) :
# Python 3.x - s'arrete au plus court iterable
list1 = [1, 2, 3, 4, 5]
list2 = [10, 20, 30] # Plus court
result = list(map(lambda x, y: x + y, list1, list2))
print(result) # [11, 22, 33] - seulement 3 elements
# La fonction doit avoir le bon nombre de parametres
def median_of_three(a, b, c):
return sorted((a, b, c))[1]
# Ceci provoque une erreur si un iterable est trop court
# list(map(median_of_three, [100, 111], [102, 117]))
# TypeError: median_of_three() missing 1 required positional argument: 'c'
Section 69.4 : Transposition avec Map (Python 2.x uniquement)
En Python 2.x, une astuce interessante permet d’utiliser None comme fonction pour transposer une matrice :
# Python 2.x uniquement
image = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = list(map(None, *image))
print(transposed) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
Cette syntaxe ne fonctionne pas en Python 3.x et genere une erreur :
# Python 3.x - ERREUR
image = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# list(map(None, *image)) # TypeError: 'NoneType' object is not callable
Alternative pour Python 3.x
Utilisez zip() pour transposer une matrice en Python 3.x :
# Python 3.x - utiliser zip() a la place
image = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
transposed = list(zip(*image))
print(transposed) # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]
# Si vous avez besoin de listes au lieu de tuples
transposed_lists = [list(row) for row in zip(*image)]
print(transposed_lists) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Section 69.5 : Series et mappage parallele
La fonction map() applique les transformations de maniere sequentielle (en serie). Voici un exemple pratique :
# Transformation en serie
insects = ['fly', 'ant', 'beetle', 'cankerworm']
describe = lambda x: x + ' is an insect'
descriptions = list(map(describe, insects))
print(descriptions)
# ['fly is an insect', 'ant is an insect', 'beetle is an insect', 'cankerworm is an insect']
# Obtenir la longueur de chaque mot
lengths = list(map(len, insects))
print(lengths) # [3, 3, 6, 10]
Mappage vraiment parallele avec multiprocessing
Pour un veritable parallelisme (utilisant plusieurs coeurs CPU), utilisez multiprocessing.Pool.map() :
from multiprocessing import Pool
import time
def heavy_computation(x):
"""Simule un calcul couteux"""
time.sleep(0.1)
return x ** 2
numbers = list(range(10))
# Execution parallele sur plusieurs coeurs
with Pool(processes=4) as pool:
results = pool.map(heavy_computation, numbers)
print(results) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Bonnes Pratiques
Voici les recommandations essentielles pour utiliser map() efficacement dans vos projets Python.
1. Preferez les fonctions nommees pour la lisibilite
# Moins lisible - lambda complexe
result = list(map(lambda x: x.strip().lower().replace(' ', '_'), strings))
# Plus lisible - fonction nommee
def normalize_string(s):
"""Normalise une chaine : trim, lowercase, underscore."""
return s.strip().lower().replace(' ', '_')
result = list(map(normalize_string, strings))
2. Utilisez les comprehensions pour les cas simples
# map() avec lambda simple
doubled = list(map(lambda x: x * 2, numbers))
# List comprehension - souvent plus lisible
doubled = [x * 2 for x in numbers]
3. Exploitez la lazy evaluation
# Bon : traitement paresseux pour grandes collections
large_data = range(1_000_000)
processed = map(expensive_function, large_data)
# Iterer sans tout charger en memoire
for item in processed:
if condition(item):
break # Arrete le traitement des que trouve
4. Combinez avec d’autres fonctions fonctionnelles
from functools import reduce
# Pipeline fonctionnel
numbers = [1, 2, 3, 4, 5]
# Filtrer, transformer, reduire
result = reduce(
lambda acc, x: acc + x,
map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)),
0
)
print(result) # 20 (4 + 16)
5. Utilisez operator pour les operations standard
from operator import add, mul, itemgetter
# Plus performant que lambda
list1 = [1, 2, 3]
list2 = [4, 5, 6]
# Au lieu de: map(lambda x, y: x + y, list1, list2)
sums = list(map(add, list1, list2))
print(sums) # [5, 7, 9]
# Extraire des cles de dictionnaires
users = [{'name': 'Alice', 'age': 30}, {'name': 'Bob', 'age': 25}]
names = list(map(itemgetter('name'), users))
print(names) # ['Alice', 'Bob']
Pieges Courants
Evitez ces erreurs frequentes lors de l’utilisation de map().
1. Oublier que l’iterateur est consomme
# ERREUR COURANTE
result = map(str.upper, ['a', 'b', 'c'])
print(list(result)) # ['A', 'B', 'C']
print(list(result)) # [] - VIDE ! L'iterateur est epuise
# SOLUTION : convertir en liste si reutilisation necessaire
result = list(map(str.upper, ['a', 'b', 'c']))
print(result) # ['A', 'B', 'C']
print(result) # ['A', 'B', 'C'] - OK
2. Ignorer les effets de bord dans la fonction
# MAUVAISE PRATIQUE - effets de bord
results = []
def bad_function(x):
results.append(x) # Effet de bord !
return x * 2
# Le map n'est pas evalue immediatement en Python 3
mapped = map(bad_function, [1, 2, 3])
print(results) # [] - VIDE car map pas encore evalue !
list(mapped) # Force l'evaluation
print(results) # [1, 2, 3]
# BONNE PRATIQUE - fonction pure
def good_function(x):
return x * 2
result = list(map(good_function, [1, 2, 3]))
3. Utiliser map() pour des operations sans retour
# ERREUR - print() retourne None
result = list(map(print, [1, 2, 3]))
# Affiche: 1, 2, 3
print(result) # [None, None, None] - Pas utile !
# SOLUTION - utiliser une boucle for
for item in [1, 2, 3]:
print(item)
4. Mauvaise gestion des exceptions
# ERREUR - une exception arrete tout
def safe_int(s):
return int(s)
data = ['1', '2', 'invalid', '4']
# list(map(safe_int, data)) # ValueError!
# SOLUTION - gerer les exceptions dans la fonction
def safe_int(s):
try:
return int(s)
except ValueError:
return None # ou une valeur par defaut
result = list(map(safe_int, data))
print(result) # [1, 2, None, 4]
# Filtrer les None si necessaire
result = [x for x in map(safe_int, data) if x is not None]
print(result) # [1, 2, 4]
Conclusion
La fonction map() est un outil fondamental de la programmation fonctionnelle en Python. Elle permet de transformer des donnees de maniere elegante, lisible et performante, tout en respectant les principes d’immutabilite et d’absence d’effets de bord.
Points cles a retenir
- Python 3.x :
map()retourne un iterateur (lazy evaluation), economisant la memoire - Plusieurs iterables :
map()peut traiter plusieurs collections en parallele - Performance : Souvent plus rapide qu’une boucle for classique grace a l’implementation en C
- Composabilite : S’integre parfaitement avec
filter(),reduce()et les comprehensions
Quand utiliser map() vs comprehensions ?
| Situation | Recommandation |
|---|---|
| Transformation simple | List comprehension |
| Fonction existante (len, str.upper) | map() |
| Plusieurs iterables | map() |
| Grandes collections | map() (lazy) |
| Logique complexe | Fonction nommee + map() |
En maitrisant map() et ses subtilites, vous ecrirez du code Python plus idiomatique, plus maintenable et plus performant.
Ressources supplementaires
In-Article Ad
Dev Mode
Mahmoud DEVO
Senior Full-Stack Developer
I'm a passionate full-stack developer with 10+ years of experience building scalable web applications. I write about Vue.js, Node.js, PostgreSQL, and modern DevOps practices.
Enjoyed this article?
Subscribe to get more tech content delivered to your inbox.
Related Articles
Differences cles entre Python 2 et Python 3 : map, round, imports et plus
Guide complet de migration Python 2 vers Python 3 : decouvrez les changements de map(), round(), imports relatifs, exec() et cmp(). Exemples pratiques et bonnes pratiques.
Recherche de valeurs dans les listes, tuples et dictionnaires Python
Apprenez a rechercher des elements dans les sequences Python : methode index(), mot-cle in, recherche dans les dictionnaires et algorithme bisect pour listes triees.
Expressions Regulieres en Python : Guide Complet pour Maitriser le Module re
Apprenez a maitriser les expressions regulieres en Python avec le module re. Decouvrez comment extraire des donnees, valider des formats, manipuler des chaines et eviter les pieges courants avec des exemples pratiques.