4.7. Utiliser des fonctions lambda

Python permet une syntaxe intéressante qui vous laisse définir des mini-fonctions d’une ligne à la volée. Empruntées à Lisp, ces fonctions dites lambda peuvent être employées partout où une fonction est nécéssaire.

Exemple 4.20. Présentation des fonctions lambda

>>> def f(x):
...     return x*2
...     
>>> f(3)
6
>>> g = lambda x: x*2  1
>>> g(3)
6
>>> (lambda x: x*2)(3) 2
6
1 Voici une fonction lambda qui fait la même chose que la fonction ordinaire précédente. Notez la syntaxe condensée : il n’y a pas de parenthèses autour de la liste d’arguments et le mot-clé return est manquant (il est implicite, la fonction complète ne pouvant être qu’une seule expression). Remarquez aussi que la fonction n’a pas de nom, mais qu’elle peut être appelée à travers la variable à laquelle elle est assignée.
2 Vous pouvez utiliser une fonction lambda sans l’assigner à une variable. Ce n’est pas forcément très utile, mais cela démontre qu’une fonction lambda est simplement une fonction en ligne.

Plus généralement, une fonction lambda est une fonction qui prend un nombre quelconque d’arguments (y compris des arguments optionnels) et retourne la valeur d’une expression unique. Les fonctions lambda ne peuvent pas contenir de commandes et elles ne peuvent contenir plus d’une expression. N’essayez pas de mettre trop de choses dans une fonction lambda, si vous avez besoin de quelque chose de complexe, définissez plutôt une fonction normale et faites la aussi longue que vous voulez.

NOTE
Les fonctions lambda sont une question de style. Les utiliser n’est jamais une nécessité, partout où vous pouvez les utiliser, vous pouvez utiliser une fonction ordinaire. Je les utilise là où je veux incorporer du code spécifique et non réutilisable sans encombrer mon code de multiples fonctions d’une seule ligne.

4.7.1. Les fonctions lambda dans le monde réel

Voici les fonctions lambda dans apihelper.py:

    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

Il y a plusieurs chose à noter ici. D’abord, nous utilisons la forme simple de l’astuce and-or, ce qui est sûr car une fonction lambda vaut toujours vrai dans un contexte booléen. (Cela ne veut pas dire qu’une fonction lambda ne peut retourner faux. La fonction est toujours vrai, sa valeur de retour peut être vrai ou fausse.)

Ensuite, nous utilisons la fonction split sans arguments. Vous l’avez déjà vu employée avec un ou deux arguments, sans arguments elle utilise les espaces comme séparateur.

Exemple 4.21. split sans arguments

>>> s = "this   is\na\ttest"  1
>>> print s
this   is
a	test
>>> print s.split()           2
['this', 'is', 'a', 'test']
>>> print " ".join(s.split()) 3
'this is a test'
1 Voici une chaîne multi-lignes définie à l’aide de caractères d’échappement au lieu de triples guillemets. \n est le retour chariot et \t le caractère de tabulation.
2 split sans arguments fait la séparation sur les espaces. Trois espaces, un retour chariot ou un caractère de tabulation reviennent à la même chose.
3 Vous pouvez normaliser les espaces en utilisant split sur une chaîne et en la joignant par join avec un espace simple comme délimiteur. C’est ce que fait la fonction info pour replier les docstring sur une seule ligne.

Mais que fait donc exactement cette fonction info avec ces fonctions lambda, ces split et ces astuces and-or ?

    processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

processFunc est maintenant une fonction, mais la fonction qu’elle est dépend de la valeur de la variable collapse. Si collapse vaut vrai, processFunc(string) repliera les espaces, sinon, processFunc(string) retournera son argument sans le modifier.

Pour faire la même chose dans un langage moins robuste, tel que Visual Basic, vous auriez sans doute créé une fonction prenant une chaîne et un argument collapse qui aurait utilisé une instruction if pour décider de replier les espaces ou non, puis aurait retourné la valeur appropriée. Cela serait inefficace car la fonction devrait prendre en compte tous les cas possibles. A chaque fois que vous l’appeleriez, elle devrait décider si elle doit replier l’espace avant de pouvoir vous donner ce que vous souhaitez. En Python, vous pouvez retirer cette prise de décision de la fonction et définir une fonction lambda taillée sur mesure pour vous donner ce que vous voulez et seulement cela. C’est plus efficace, plus élégant et moins sujet à des erreurs dans l’ordre des arguments.

Pour en savoir plus sur les fonctions lambda