Skip to article frontmatterSkip to article content

lambda est une expression, pas une instruction
qui permet de créer un objet fonction anonyme et à la volée

# un objet fonction 
# qui n'a pas de nom
lambda x: x**2
<function __main__.<lambda>(x)>
# mais que je peux appeler
(lambda x: x**2)(10)
100
# comme si j'avait fait
def anonymous(x):
    return x**2

anonymous(10)
100

lambda : une expression

lambda vs def

def foo(x):
    return x*x
foo
<function __main__.foo(x)>
foo = lambda x: x*x
foo
<function __main__.<lambda>(x)>

limitation de lambda

lambda arg1, arg2, … argN : expression using args
f = lambda x: x+1
f(1)
2
(lambda x: x+1)(12)
13

exemples d’utilisation

# pour appeler un objet fonction
# c'est la syntaxe habituelle
def call(func, a, b):
    return(func(a, b))

# j'appelle l'addition sur ces deux nombres
call(lambda a, b: a + b, 3, 5)
8
# pareil avec la multiplication
call(lambda a, b: a * b, 3, 5)
15

application au tri

Rappel :

sample = "This is a test string from Andrew".split()
sample
['This', 'is', 'a', 'test', 'string', 'from', 'Andrew']
# une copie triée de sample
sorted(sample)
['Andrew', 'This', 'a', 'from', 'is', 'string', 'test']
# avec un autre critère
sorted(sample, key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']
# pareil que
sorted(sample, key=lambda s: str.lower(s))
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

ou encore avec une autree donnée

student_marks = [('marc', 12), ('eric', 15), ('jean', 12), ('gabriel', 18)]

# on n'indique pas comment trier : c'est l'ordre "naturel" des tuples
sorted(student_marks)
[('eric', 15), ('gabriel', 18), ('jean', 12), ('marc', 12)]
# pour trier sur la note cette fois
sorted(student_marks, key=lambda student_tuple: student_tuple[1])
[('marc', 12), ('jean', 12), ('eric', 15), ('gabriel', 18)]
# remarque:
# des utilitaires sont disponibles aussi
# dans le module standard `operator` 
import operator
sorted(student_marks, key=operator.itemgetter(1))
[('marc', 12), ('jean', 12), ('eric', 15), ('gabriel', 18)]

reverse() et reversed()

source = [1, 10, 100, 1000]
source.reverse()
source
[1000, 100, 10, 1]
reversed(source)
<list_reverseiterator at 0x7f3cc82f27a0>
list(reversed(source))
[1, 10, 100, 1000]

map() et filter()

rappel : appliquent une fonction à un itérable

L = [1, 2, 3, 4]
m = map(lambda x: x**2, L)
# le résultat est un itérateur
m
<map at 0x7f3cc82f0520>
# pour voir le résultat la liste on
# peut par exemple transformer
# explicitement en list()
list(m)
[1, 4, 9, 16]
# si on essaie une deuxième fois
# il ne se passe plus rien car on a déjà itéré sur m
list(m)
[]
m = map(lambda x: x**2, L)
for i in m: 
    print(i, end=' ')
1 4 9 16 
source = range(1, 5)
f = filter(lambda x: x%2 == 0, 
           map(lambda x:x**2, source))

# f est bien un itérateur
f is iter(f)
True
list(f)
[4, 16]

cette forme est toutefois passée de mode au profit des expressions génératrices

# ceci est vraiment équivalent 
g = (x**2 for x in source
     if x%2 == 0)

g is iter(g)
True
list(g)
[4, 16]

introspection (avancé)

lecture d’attributs

def f(name="jean"):
    """le docstring"""
    pass
f.__name__
'f'
f.__doc__
'le docstring'
f.__code__
<code object f at 0x7f3cc82fa3f0, file "/tmp/ipykernel_2575/651212823.py", line 1>
f.__module__
'__main__'
f.__defaults__
('jean',)

aller plus loin