Comment ne PAS utiliser une fonction anonyme (ou lambda) en Python 5


Dans le dernier article sur les lambdas, j’avais précisé que les lambdas étaient une question de style et qu’on pouvait faire sans. Voici différentes stratégies pour s’en passer.

Utiliser une inner function

En python on peut définir et exécuter à la volée une fonction dans une autre fonction/méthode ou une classe.

class Banane(object):
 
    def blougou(): # pas de self :-)
        print "Sens giratoir inversé"
 
    blougou() # on peut appeler une fonction en dehors d'une méthode
 
    def methode(self): # une vraie méthode
        print "Vive Edgar Morin"
 
        # on peut définir une fonction dans une méthode
        def moukrene():
            print "A la glaviouse"
 
        moukrene()

Et ça donne:

Sens giratoir inversé # affichage à l'import
>>> Banane().methode()
Vive Edgar Morin
A la glaviouse

Préremplissez des arguments

Le module functools fournit tout un tas de goodies pour faire mumuse avec les fonctions, et notamment la fonction partial() qui prend une fonction en argument, et des arguments à passer à la fonction qu’on lui a passé en argument. Vous suivez ?

On s’en sert quand on veut utiliser une fonction, mais qu’on sait d’avance quels arguments on va lui passer:

>>> from functools import partial
>>> sum
<built-in function sum>
>>> sum([2, 2])
4
>>> mini_sum = partial(sum, [2, 2])
>>> mini_sum()
4

On pas besoin de donner tous les arguments de la fonction à enrober: on peut passer les autres après.

Comme partial() retourne une fonction prête à être appelée, on peut l’utiliser là où on utiliserait une lambda:

>>> from __future__ import print_function
>>> def profit(etape1="On vol des caleçons", etape2=lambda: print('...')):
...         print(etape1)
...         etape2()
...     
>>> profit()
On vol des caleçons
...

Se tranforme en:

>>> def profit(etape1="On vol des caleçons", etape2=partial(print, '...')):
...         print(etape1)
...         etape2()
...     
>>> profit()
On vol des caleçons
...

Utiliser les fonctions derrières les opérations de base

Quand vous utilisez un + ou un [], il s’agit ni plus ni moins d’une syntaxe raccourcie pour l’appel d’une fonction. Et Python vous laisse accéder à ces fonctions à travers le module operator.

>>> for operation in (lambda x: x[0], lambda x: x * 3):
    print(operation(ls))
...     
a
['a', 3, 'a', 3, 'a', 3]
>>> from operator import itemgetter, mul
>>> for operation in (itemgetter(0), partial(mul, 3)):
    print(operation(ls))
...     
a
['a', 3, 'a', 3, 'a', 3]

Le module operator est très riche: opérations logiques (incluant la négation), manipulation de slices, maths de base, set/get d’attributs/de clés/d’index… Il y a de quoi faire.

Mettez à la poubelle map et filter

Map permet d’appliquer une fonction a un itérable. Filter permet de choisir les éléments d’un itérable selon un critère pour former un autre itérable.

>>> nombres = range(10)
>>> paires = filter(lambda x: not x % 2, nombres)
>>> paires
[0, 2, 4, 6, 8]
>>> paires_au_carres = map(lambda x: x * x, paires)
>>> paires_au_carres
[0, 4, 16, 36, 64]

Les listes en intention remplacent avantageusement ces deux fonctions (je crois d’ailleurs qu’elles sont retirées des built-in en Python 3):

>>> [x * x for x in range(10) if not x % 2]
[0, 4, 16, 36, 64]

Je ne suis pas un allergique aux lambdas, et je les utilise assez souvent, mais il est bon de savoir qu’il existe des alternatives.

5 thoughts on “Comment ne PAS utiliser une fonction anonyme (ou lambda) en Python

  • Kontre

    Juste en passant, c’est pas “je les utilisent assez souvent” dans la conclusion mais “je les utilise assez souvent”.

  • Aenor

    Hello,

    est il préférable d’utiliser partial ou un lambda pour pré remplir des arguements ?
    Je vais fouiller le net également.
    J’ai utilisé des lambdas sans les maitriser dans des boutons de tkinter, parce que ceux ci ne peuvent prendre en commande que des fonctions sans arguments.

    Merci d’avance si jamais j’ai une réponse,
    Bonne soirée

  • Sam Post author

    Il n’y a pas de meilleure manière, c’est une question de style. Lambda est plus rapide, partial indique clairement l’intention de la ligne de code.

  • ast

    bonjour

    En python 3.5, l’appel de Banane().methode() ne donne pas la même chose que dans cet article.

    >>> Banane().methode()
    Vive Edgar Morin
    A la glaviouse

    et c’est mieux comme ça, il y a aucune raison de lancer blougou quand on appelle une méthode de Banane()

    ‘Sens giratoir inversé’ apparait quand l’interpréteur parse la classe Banane

Leave a comment

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.