Chapitre 18 : Fonctions Lambda
Fonctions anonymes, lambda, sorted, map, filter
1. Quoi : Les Fonctions Lambda
Une fonction lambda (ou fonction anonyme) est une petite fonction définie sans nom, en une seule ligne. Elle peut prendre plusieurs arguments, mais ne peut avoir qu'une seule expression.
La valeur de cette expression est ce que la fonction retourne implicitement.
2. Pourquoi : Des fonctions "jetables"
Les fonctions lambda sont utiles lorsque vous avez besoin d'une petite fonction pour une courte durée, typiquement comme argument pour une autre fonction (une fonction d'ordre supérieur).
- Concises : Elles permettent d'écrire du code plus court pour des opérations simples.
- Immédiates : Vous les définissez là où vous en avez besoin, sans avoir à "polluer" votre code avec la définition d'une fonction
defque vous n'utiliserez qu'une seule fois.
Elles sont très couramment utilisées avec des fonctions comme sorted(), map(), et filter().
3. Comment : La Syntaxe
La syntaxe de base est : lambda arguments: expression
lambda: Le mot-clé qui déclare une fonction anonyme.arguments: Les paramètres de la fonction, séparés par des virgules (comme pour une fonctiondef).expression: Une unique expression dont la valeur sera retournée.
Exemple : une fonction qui ajoute 10
Version def
def add_ten(x):
return x + 10
Version lambda
add_ten_lambda = lambda x: x + 10
# Les deux s'appellent de la même manière
print(add_ten(5)) # 15
print(add_ten_lambda(5)) # 15
Assigner une lambda à une variable (comme ci-dessus) est possible, mais c'est souvent un anti-pattern. Si une fonction mérite un nom, il vaut mieux utiliser def.
4. Cas d'usage principaux
A. Avec sorted()
La fonction sorted() peut prendre un argument nommé key qui est une fonction. Cette fonction est appliquée à chaque élément avant de faire la comparaison pour le tri. Les lambdas sont parfaites pour cela.
Exemple : Trier une liste de tuples par leur deuxième élément
points = [(1, 5), (9, 2), (4, 7)]
# On veut trier par le deuxième élément de chaque tuple (5, 2, 7)
# La fonction key doit donc prendre un tuple 'p' et retourner p[1]
sorted_points = sorted(points, key=lambda p: p[1])
print(sorted_points) # [(9, 2), (1, 5), (4, 7)]
Exemple : Trier une liste de dictionnaires par âge
users = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35},
]
# La clé de tri est l'âge de l'utilisateur
sorted_users = sorted(users, key=lambda u: u["age"])
print(sorted_users)
# [{'name': 'Bob', 'age': 25}, {'name': 'Alice', 'age': 30}, {'name': 'Charlie', 'age': 35}]
B. Avec map()
La fonction map(function, iterable) applique une fonction à chaque élément d'un itérable et retourne un objet map (que l'on peut convertir en liste).
Exemple : Mettre au carré chaque nombre d'une liste
numbers = [1, 2, 3, 4]
# La fonction lambda x: x*x est appliquée à chaque nombre
squared_numbers_map = map(lambda x: x * x, numbers)
# On convertit l'objet map en liste pour voir le résultat
squared_numbers_list = list(squared_numbers_map)
print(squared_numbers_list) # [1, 4, 9, 16]
Note : Dans ce cas précis, une compréhension de liste
[x*x for x in numbers]est souvent considérée comme plus "pythonic" et plus lisible.
C. Avec filter()
La fonction filter(function, iterable) retourne un objet filter contenant uniquement les éléments de l'itérable pour lesquels la fonction retourne True.
Exemple : Garder uniquement les nombres pairs
numbers = [1, 2, 3, 4, 5, 6]
# La fonction lambda n: n % 2 == 0 retourne True si n est pair
even_numbers_filter = filter(lambda n: n % 2 == 0, numbers)
# On convertit en liste
even_numbers_list = list(even_numbers_filter)
print(even_numbers_list) # [2, 4, 6]
Note : Ici aussi, une compréhension de liste
[n for n in numbers if n % 2 == 0]est une alternative très populaire.
5. Quand ne PAS les utiliser ?
- Pour des fonctions complexes : Une lambda est limitée à une seule expression. Si votre logique nécessite plusieurs lignes, des
if/elif/elsecomplexes ou des boucles, utilisez une fonctiondefnormale. - Quand la lisibilité en pâtit : Une lambda très longue ou obscure est pire qu'une fonction
defbien nommée. Le but est d'améliorer la clarté, pas de l'obscurcir. - Si vous l'assignez à un nom : Comme dit plus haut,
my_func = lambda x: ...est fonctionnel, maisdef my_func(x): ...est plus clair et fournit de meilleures informations pour le débogage.
Exercices :
Exercice 18 - Tri de Données Complexes
Objectif
Cet exercice a pour but de vous faire utiliser des fonctions lambda comme clé de tri (key) avec la fonction sorted() pour trier une liste de dictionnaires selon différents critères.
Contexte
Vous avez une liste de dictionnaires représentant des produits. Chaque produit a un nom, un prix et une note de popularité. Vous devez trier cette liste de différentes manières pour l'afficher sur un site e-commerce.
Énoncé
-
Créez un nouveau fichier Python nommé
product_sorter.py. -
Initialisez la liste de produits suivante :
products = [
{"name": "Laptop", "price": 1200, "popularity": 8},
{"name": "Mouse", "price": 25, "popularity": 10},
{"name": "Keyboard", "price": 75, "popularity": 9},
{"name": "Monitor", "price": 300, "popularity": 7},
] -
Triez les produits par prix (du moins cher au plus cher) :
- Utilisez la fonction
sorted()avec une fonctionlambdacommekey. La lambda doit extraire lepricede chaque dictionnaire. - Stockez le résultat dans une variable
sorted_by_price. - Affichez le résultat de manière lisible.
- Utilisez la fonction
-
Triez les produits par popularité (du plus populaire au moins populaire) :
- Utilisez à nouveau
sorted(), mais cette fois, lalambdadoit extraire lapopularity. - Pour trier en ordre décroissant, utilisez l'argument
reverse=Truede la fonctionsorted(). - Stockez le résultat dans
sorted_by_popularity. - Affichez le résultat.
- Utilisez à nouveau
-
Triez les produits par la longueur de leur nom (du plus court au plus long) :
- Utilisez
sorted()et unelambdaqui calcule la longueur (len()) dunamede chaque produit. - Stockez le résultat dans
sorted_by_name_length. - Affichez le résultat.
- Utilisez
-
Filtrez les produits dont le prix est supérieur à 300 euros:
- Utilisez
filter()et unelambdapour obtenir la liste dont les produits ont un prix supérieur à 300€ - N'oubliez pas de convertir en liste le retour de la fonction
filter() - Stockez le résultat dans
price_over_300 - Affichez le résultat
- Utilisez
-
Transformez la liste de produits en une liste dans le format sera le suivant :
nom du produit:prix- Sans utiliser la compréhension de liste mais la fonction
map(), transformer la liste de produit en une liste dont chaque élément aura le format : "nom : prix" - Stockez le résultat dans
product_with_price_only - Affichez le résultat
- Sans utiliser la compréhension de liste mais la fonction
Résultat Attendu
--- Sorted by Price (Ascending) ---
[{'name': 'Mouse', 'price': 25, 'popularity': 10}, {'name': 'Keyboard', 'price': 75, 'popularity': 9}, {'name': 'Monitor', 'price': 300, 'popularity': 7}, {'name': 'Laptop', 'price': 1200, 'popularity': 8}]
--- Sorted by Popularity (Descending) ---
[{'name': 'Mouse', 'price': 25, 'popularity': 10}, {'name': 'Keyboard', 'price': 75, 'popularity': 9}, {'name': 'Laptop', 'price': 1200, 'popularity': 8}, {'name': 'Monitor', 'price': 300, 'popularity': 7}]
--- Sorted by Name Length (Ascending) ---
[{'name': 'Mouse', 'price': 25, 'popularity': 10}, {'name': 'Laptop', 'price': 1200, 'popularity': 8}, {'name': 'Monitor', 'price': 300, 'popularity': 7}, {'name': 'Keyboard', 'price': 75, 'popularity': 9}]
--- Filter by Price over 300€ ---
[{'name': 'Laptop', 'price': 1200, 'popularity': 8}]
--- Map in specific string ---
['Laptop : 1200€', 'Mouse : 25€', 'Keyboard : 75€', 'Monitor : 300€']
Cliquez ici pour voir un exemple de code de solution
# product_sorter.py
products = [
{"name": "Laptop", "price": 1200, "popularity": 8},
{"name": "Mouse", "price": 25, "popularity": 10},
{"name": "Keyboard", "price": 75, "popularity": 9},
{"name": "Monitor", "price": 300, "popularity": 7},
]
# 1. Tri par prix (croissant)
# La lambda prend un produit 'p' et retourne son prix p['price'].
sorted_by_price = sorted(products, key=lambda p: p["price"])
print("--- Sorted by Price (Ascending) ---")
print(sorted_by_price)
# 2. Tri par popularité (décroissant)
# La lambda prend un produit 'p' et retourne sa popularité p['popularity'].
# L'argument reverse=True inverse l'ordre du tri.
sorted_by_popularity = sorted(products, key=lambda p: p["popularity"], reverse=True)
print("\n--- Sorted by Popularity (Descending) ---")
print(sorted_by_popularity)
# 3. Tri par longueur du nom (croissant)
# La lambda prend un produit 'p' et retourne la longueur de son nom len(p['name']).
sorted_by_name_length = sorted(products, key=lambda p: len(p["name"]))
print("\n--- Sorted by Name Length (Ascending) ---")
print(sorted_by_name_length)
# 4. Filter by Price over 300€
price_over_300 = list(filter(lambda p: p["price"] > 300, products))
print("\n--- Filter by Price over 300€ ---")
print(price_over_300)
# 5. Map in specific string
product_with_price_only = list(map(lambda p: f"{p['name']} : {p['price']}€", products))
print("\n--- Map in specific string ---")
print(product_with_price_only)