def carre(x):
return x ** 2
print(carre(5))25
Les fonctions lambda sont des fonctions anonymes que l’on définit en une ligne, là où on en a besoin. Elles sont omniprésentes dès qu’on utilise sorted, filter, map, ou des fonctions qui attendent un autre fonction en paramètre. Le TOSA Avancé les teste systématiquement.
Une lambda est une fonction sans nom, définie en une expression unique.
def carre(x):
return x ** 2
print(carre(5))25
carre = lambda x: x ** 2
print(carre(5))25
lambda x, y : x + y
│ │ │
│ │ expression (le retour)
│ paramètres
mot-clé
Points à noter :
lambda remplace def.return : l’expression après : est implicitement renvoyée.if/else en bloc, pas de boucle, pas de print).Dans 99 % des cas, on utilise une lambda pour passer un petit comportement à une fonction qui en attend un.
sorted() — le cas #1Trier selon un critère :
mots = ["banane", "kiwi", "pomme", "fraise"]
# Par longueur
print(sorted(mots, key=lambda m: len(m)))
# Par dernière lettre
print(sorted(mots, key=lambda m: m[-1]))['kiwi', 'pomme', 'banane', 'fraise']
['banane', 'pomme', 'fraise', 'kiwi']
etudiants = [("Alice", 14), ("Bob", 8), ("Charlie", 17), ("Diana", 9)]
# Par note
print(sorted(etudiants, key=lambda t: t[1]))
# Par note décroissante
print(sorted(etudiants, key=lambda t: t[1], reverse=True))[('Bob', 8), ('Diana', 9), ('Alice', 14), ('Charlie', 17)]
[('Charlie', 17), ('Alice', 14), ('Diana', 9), ('Bob', 8)]
etudiants = [
("Alice", "A", 14),
("Bob", "B", 17),
("Charlie", "A", 17),
("Diana", "B", 14),
]
# Par note décroissante, puis par nom
classement = sorted(etudiants, key=lambda t: (-t[2], t[0]))
for x in classement:
print(x)('Bob', 'B', 17)
('Charlie', 'A', 17)
('Alice', 'A', 14)
('Diana', 'B', 14)
La clé lambda t: (-t[2], t[0]) renvoie un tuple : tri primaire par -note (équivalent à décroissant), secondaire par nom.
filter()nombres = [1, -2, 3, -4, 5, -6, 7]
# Ne garder que les positifs
positifs = list(filter(lambda n: n > 0, nombres))
print(positifs)[1, 3, 5, 7]
filter/map
Une compréhension fait la même chose, plus lisiblement :
nombres = [1, -2, 3, -4, 5, -6, 7]
# ✅ Préférez
positifs = [n for n in nombres if n > 0]
print(positifs)[1, 3, 5, 7]
filter et map restent utiles dans un style fonctionnel ou quand on a déjà la fonction sous la main (fonction nommée existante).
map()nombres = [1, 2, 3, 4]
# Carrés
carres = list(map(lambda n: n ** 2, nombres))
print(carres)[1, 4, 9, 16]
Équivalent : [n ** 2 for n in nombres].
max() / min()etudiants = [
{"nom": "Alice", "note": 14},
{"nom": "Bob", "note": 17},
{"nom": "Eve", "note": 12},
]
meilleur = max(etudiants, key=lambda e: e["note"])
print("Meilleur :", meilleur)
faible = min(etudiants, key=lambda e: e["note"])
print("Plus faible :", faible)Meilleur : {'nom': 'Bob', 'note': 17}
Plus faible : {'nom': 'Eve', 'note': 12}
reduce() (pour culture)Le module functools propose reduce qui agrège une liste selon une fonction binaire :
from functools import reduce
# Somme (équivalent à sum)
total = reduce(lambda a, b: a + b, [1, 2, 3, 4, 5])
print(total)
# Produit
produit = reduce(lambda a, b: a * b, [1, 2, 3, 4, 5])
print(produit)
# Maximum (équivalent à max)
plus_grand = reduce(lambda a, b: a if a > b else b, [3, 1, 4, 1, 5, 9, 2])
print(plus_grand)15
120
9
En pratique, sum, min, max sont préférés à reduce quand ils existent.
# Deux paramètres
additionner = lambda a, b: a + b
print(additionner(3, 5))
# Trois paramètres
volume = lambda L, l, h: L * l * h
print(volume(2, 3, 4))
# Zéro paramètre
constante = lambda: 42
print(constante())8
24
42
Les lambdas sont volontairement limitées pour rester lisibles :
Pas de return, pas de boucle, pas de if/elif en bloc.
# ❌ Impossible
f = lambda x:
if x > 0:
return x
else:
return -x
# ✅ Possible avec une ternaire
f = lambda x: x if x > 0 else -x# ❌ Impossible
f = lambda x: int -> int: x * 2
# ✅ Utilisez une fonction normale si vous voulez annoter
def doubler(x: int) -> int:
return x * 2Une lambda ne peut pas être documentée. Si votre fonction mérite une docstring, n’utilisez pas lambda.
def : pour toute fonction réutilisée, complexe, ou méritant un nom.Quand vous hésitez, préférez def — c’est plus lisible.
# ✅ Clé de tri simple, jetable
sorted(notes, key=lambda n: n["score"])
# ✅ Filtre ponctuel
list(filter(lambda x: x > 0, valeurs))
# ✅ Fonction callback courte
bouton.on_click = lambda: print("clic !")# ❌ Affecter une lambda à un nom — utilisez def
carre = lambda x: x ** 2
# → Préférez :
def carre(x):
return x ** 2La PEP 8 dit explicitement : « Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier. »
Raison : def carre(x): return x ** 2 est aussi court mais plus lisible et débogable (la fonction a un vrai nom, visible dans les traces d’erreur).
Les lambdas sont faites pour être passées en argument, pas stockées sous un nom.
Un cas surprenant qui tombe parfois au TOSA :
# Créer une liste de fonctions qui multiplient par 1, 2, 3 ?
multiplicateurs = [lambda x: x * i for i in range(1, 4)]
# Problème !
for m in multiplicateurs:
print(m(10)) # on s'attend à 10, 20, 3030
30
30
Pourquoi ? Les 3 lambdas capturent la même variable i, qui vaut 3 à la fin de la boucle.
Solution : forcer la capture par une valeur par défaut.
multiplicateurs = [lambda x, i=i: x * i for i in range(1, 4)]
for m in multiplicateurs:
print(m(10)) # 10, 20, 30 comme attendu10
20
30
i=i évalue i au moment de la création de la lambda et le fige.
operator : alternative aux lambdasPour des lambdas ultra-simples comme lambda t: t[1] ou lambda o: o.note, le module operator offre une alternative plus rapide et plus lisible :
from operator import itemgetter, attrgetter
etudiants = [("Alice", 14), ("Bob", 17), ("Eve", 12)]
# Avec lambda
print(sorted(etudiants, key=lambda t: t[1]))
# Avec itemgetter (mieux)
print(sorted(etudiants, key=itemgetter(1)))[('Eve', 12), ('Alice', 14), ('Bob', 17)]
[('Eve', 12), ('Alice', 14), ('Bob', 17)]
itemgetter(1) renvoie une fonction équivalente à lambda t: t[1] mais plus rapide (implémentée en C).
attrgetter("attribut") est l’équivalent pour accéder à un attribut d’objet (voir POO).
Que fait lambda x: x * 2 ?
x * 2x * 2"x * 2"a) — crée une fonction anonyme qui attend x et renvoie x * 2. Il faut l’appeler pour obtenir le résultat.
f = lambda x: x * 2
print(f) # objet fonction
print(f(5)) # appel → 10<function <lambda> at 0x0000015FA3014FE0>
10
Quelle syntaxe est invalide ?
lambda x: x + 1lambda x, y: x + ylambda: 42lambda x: return x + 1d) — pas de return dans une lambda. L’expression après : est implicitement renvoyée. La bonne forme est lambda x: x + 1.
f = lambda x: return x + 1Cell In[16], line 1 f = lambda x: return x + 1 ^ SyntaxError: invalid syntax
Que renvoie sorted([3, 1, 2], key=lambda x: -x) ?
[1, 2, 3][3, 2, 1][-3, -2, -1]b) [3, 2, 1] — trier x par -x croissant revient à trier x décroissant. Équivalent à reverse=True.
print(sorted([3, 1, 2], key=lambda x: -x))[3, 2, 1]
Quelle expression est équivalente à list(map(lambda x: x * 2, [1, 2, 3])) ?
[x * 2 in [1, 2, 3]][x * 2 for x in [1, 2, 3]]map([1, 2, 3], x * 2)[1, 2, 3] * 2b) — la compréhension est plus lisible et équivalente : [x * 2 for x in [1, 2, 3]].
print(list(map(lambda x: x * 2, [1, 2, 3])))
print([x * 2 for x in [1, 2, 3]])[2, 4, 6]
[2, 4, 6]
Que renvoie sorted(["banane", "kiwi", "pomme"], key=lambda m: len(m)) ?
["banane", "kiwi", "pomme"]["kiwi", "pomme", "banane"]["kiwi", "banane", "pomme"]["pomme", "banane", "kiwi"]b) ["kiwi", "pomme", "banane"] — tri par longueur croissante : kiwi (4), pomme (5), banane (6).
print(sorted(["banane", "kiwi", "pomme"], key=lambda m: len(m)))['kiwi', 'pomme', 'banane']
Quelle affirmation est FAUSSE ?
print() et un returnc) — une lambda n’a pas de return explicite (pas autorisé), et elle ne peut contenir qu’une seule expression. Pas de print suivi d’autre chose.
Que recommande la PEP 8 ?
def à l’affectation nom = lambda...c) — si vous avez besoin d’une fonction nommée, utilisez def. Les lambdas sont faites pour être passées comme argument, pas stockées.
# ❌ Déconseillé par PEP 8
carre = lambda x: x ** 2
# ✅ Recommandé
def carre(x):
return x ** 2Soit une liste de produits :
produits = [
{"nom": "Pain", "prix": 1.20, "stock": 50},
{"nom": "Lait", "prix": 0.95, "stock": 100},
{"nom": "Fromage", "prix": 4.50, "stock": 20},
{"nom": "Vin", "prix": 12.0, "stock": 5},
{"nom": "Miel", "prix": 7.80, "stock": 15},
]En utilisant des lambdas, produisez 4 tris différents :
produits = [
{"nom": "Pain", "prix": 1.20, "stock": 50},
{"nom": "Lait", "prix": 0.95, "stock": 100},
{"nom": "Fromage", "prix": 4.50, "stock": 20},
{"nom": "Vin", "prix": 12.0, "stock": 5},
{"nom": "Miel", "prix": 7.80, "stock": 15},
]
# 4 tris à produire...produits = [
{"nom": "Pain", "prix": 1.20, "stock": 50},
{"nom": "Lait", "prix": 0.95, "stock": 100},
{"nom": "Fromage", "prix": 4.50, "stock": 20},
{"nom": "Vin", "prix": 12.0, "stock": 5},
{"nom": "Miel", "prix": 7.80, "stock": 15},
]
print("Par prix croissant :")
for p in sorted(produits, key=lambda x: x["prix"]):
print(f" {p['nom']:<10} {p['prix']:>6.2f} €")
print("\nPar stock décroissant :")
for p in sorted(produits, key=lambda x: x["stock"], reverse=True):
print(f" {p['nom']:<10} {p['stock']}")
print("\nPar nom :")
for p in sorted(produits, key=lambda x: x["nom"]):
print(f" {p['nom']}")
print("\nPar valeur totale en stock (décroissante) :")
for p in sorted(produits, key=lambda x: x["prix"] * x["stock"], reverse=True):
valeur = p["prix"] * p["stock"]
print(f" {p['nom']:<10} {valeur:>7.2f} €")Par prix croissant :
Lait 0.95 €
Pain 1.20 €
Fromage 4.50 €
Miel 7.80 €
Vin 12.00 €
Par stock décroissant :
Lait 100
Pain 50
Fromage 20
Miel 15
Vin 5
Par nom :
Fromage
Lait
Miel
Pain
Vin
Par valeur totale en stock (décroissante) :
Miel 117.00 €
Lait 95.00 €
Fromage 90.00 €
Pain 60.00 €
Vin 60.00 €
À partir d’une liste de nombres, produisez en une ligne pour chaque cas :
nombres = list(range(1, 101))
# 1. Pairs
pairs = ...
# 2. Multiples de 3 entre 10 et 100
mult3 = ...
# 3. Premiers à 1 chiffre
premiers = list(filter(lambda n: n in (2, 3, 5, 7), nombres))nombres = list(range(1, 101))
# 1. Pairs
pairs = list(filter(lambda n: n % 2 == 0, nombres))
print("Pairs (10 premiers) :", pairs[:10])
# 2. Multiples de 3 entre 10 et 100
mult3 = list(filter(lambda n: n % 3 == 0 and 10 <= n <= 100, nombres))
print("Multiples de 3 :", mult3)
# 3. Premiers à 1 chiffre
premiers = list(filter(lambda n: n in (2, 3, 5, 7), nombres))
print("Premiers :", premiers)Pairs (10 premiers) : [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Multiples de 3 : [12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99]
Premiers : [2, 3, 5, 7]
nombres = list(range(1, 101))
pairs = [n for n in nombres if n % 2 == 0]
mult3 = [n for n in nombres if n % 3 == 0 and 10 <= n <= 100]
premiers = [n for n in nombres if n in (2, 3, 5, 7)]
print("Pairs (10 premiers) :", pairs[:10])
print("Multiples de 3 :", mult3[:10], "...")
print("Premiers :", premiers)Pairs (10 premiers) : [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Multiples de 3 : [12, 15, 18, 21, 24, 27, 30, 33, 36, 39] ...
Premiers : [2, 3, 5, 7]
max avec critère dynamiqueÉcrivez une fonction meilleur(etudiants, critere) qui renvoie l’étudiant ayant le score le plus haut selon un critère donné (nom d’attribut).
Exemple :
etudiants = [
{"nom": "Alice", "maths": 14, "francais": 18},
{"nom": "Bob", "maths": 17, "francais": 11},
{"nom": "Eve", "maths": 12, "francais": 15},
]
meilleur(etudiants, "maths") # → Bob
meilleur(etudiants, "francais") # → Alicedef meilleur(etudiants, critere):
...
etudiants = [
{"nom": "Alice", "maths": 14, "francais": 18},
{"nom": "Bob", "maths": 17, "francais": 11},
{"nom": "Eve", "maths": 12, "francais": 15},
]
print(meilleur(etudiants, "maths"))
print(meilleur(etudiants, "francais"))def meilleur(etudiants, critere):
return max(etudiants, key=lambda e: e[critere])
etudiants = [
{"nom": "Alice", "maths": 14, "francais": 18},
{"nom": "Bob", "maths": 17, "francais": 11},
{"nom": "Eve", "maths": 12, "francais": 15},
]
print(meilleur(etudiants, "maths"))
print(meilleur(etudiants, "francais")){'nom': 'Bob', 'maths': 17, 'francais': 11}
{'nom': 'Alice', 'maths': 14, 'francais': 18}
from operator import itemgetter
def meilleur(etudiants, critere):
return max(etudiants, key=itemgetter(critere))
etudiants = [
{"nom": "Alice", "maths": 14, "francais": 18},
{"nom": "Bob", "maths": 17, "francais": 11},
]
print(meilleur(etudiants, "maths")){'nom': 'Bob', 'maths': 17, 'francais': 11}
C’est équivalent et plus rapide sur de grandes listes.
Que s’affiche-t-il ? Expliquez, puis corrigez le code pour obtenir 10 20 30.
fonctions = [lambda: i * 10 for i in range(1, 4)]
for f in fonctions:
print(f(), end=" ")Exécutez le code et expliquez le résultat. Corrigez-le ensuite.
Sortie incorrecte :
fonctions = [lambda: i * 10 for i in range(1, 4)]
for f in fonctions:
print(f(), end=" ")30 30 30
Pourquoi ? Les 3 lambdas capturent la même variable i, qui vaut 3 à la fin de la boucle. Tous donnent donc 3 * 10 = 30.
Correction : forcer la capture avec un paramètre par défaut.
fonctions = [lambda i=i: i * 10 for i in range(1, 4)]
for f in fonctions:
print(f(), end=" ")10 20 30
i=i fige la valeur courante de i au moment de la création de chaque lambda. C’est un piège fréquent quand on génère des lambdas dans une boucle.
return explicite.sorted(..., key=lambda ...), filter, map, max(..., key=...), min(..., key=...).key=lambda t: (-t[1], t[0]) — tuple avec signes.if/elif en bloc, pas de docstring, pas d’annotations.def.map/filter avec lambda.operator.itemgetter(i) et attrgetter("x") : alternatives plus rapides.lambda x=x: ... pour figer la valeur courante dans une boucle.← Chapitre précédent : *args et **kwargs • Chapitre suivant : POO (1/2) →