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)100lambda : une expression¶
elle peut donc apparaître
là où une fonction classique ne peut pastypiquement à l’intérieur d’une expression
par contre pas trop adapté pour du code compliqué
doit pouvoir être écrit sous forme d’une seule expression
lambda vs def¶
les deux formes suivantes sont donc équivalentes
def foo(x):
return x*x
foo<function __main__.foo(x)>foo = lambda x: x*x
foo<function __main__.<lambda>(x)>limitation de lambda¶
le corps d’une fonction lambda
doit tenir sur une seule expressionuniquement applicable à des fonctions simples
pas de déclaration de variable locale
pas d’impact sur la portée des variables
forme générale
lambda arg1, arg2, … argN : expression using argsf = lambda x: x+1
f(1)2(lambda x: x+1)(12)13exemples 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)15application au tri¶
Rappel :
sort()est une méthode qui trie les listes en placesorted()est une fonction built-in qui trie n’importe quel itérable et retourne un nouvel itérateurargument
key:
une fonction pour spécifier le critère de tri
typiquement une fonction lambdaargument
reverse:
booléen qui définit l’ordre de tri
par défautreverse=False: tri ascendant
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()¶
un schéma analogue existe
pour renverser / retourner une listelist.reverse()comme méthode
sur les listes qui retourne en placereversed()comme fonction builtin qui renvoie
un itérateur pour parcourir à l’envers
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
map(func, iter)applique la fonction
funcà chaque élément deiterretourne (un itérateur sur) les valeurs retournées par
func
filter(func, iter)similaire à
map, mais retourne seulement les valeurs
qui sont vraies (techniquement, telles quebool(val) == True)
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)Truelist(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)Truelist(g)[4, 16]introspection (avancé)¶
en Python tout est un objet
on peut accéder à tous les attributs d’un objeten particulier donc pour les objets de type fonction
modifier directement les attributs n’est pas recommandé,
sauf si on comprend vraiment ce que l’on faitpar contre c’est intéressant en lecture
pour comprendre les détails d’implémentation
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¶
si le sujet vous intéresse
voyez le module inspect dans la librairie standard