121 votes

Qu'est-il préférable d'utiliser : les fonctions lambda ou les fonctions imbriquées ('def') ?

J'utilise principalement des fonctions lambda mais parfois des fonctions imbriquées qui semblent fournir le même comportement.

Voici quelques exemples triviaux où ils font fonctionnellement la même chose si l'un ou l'autre se trouvait dans une autre fonction :

Fonction lambda

>>> a = lambda x : 1 + x
>>> a(5)
6

Fonction imbriquée

>>> def b(x): return 1 + x

>>> b(5)
6

Y a-t-il des avantages à utiliser l'un plutôt que l'autre ? (Performances ? Lisibilité ? Limites ? Cohérence ? etc.)

Est-ce que cela a de l'importance ? Si ce n'est pas le cas, cela viole-t-il le principe de Python ?

Il devrait y avoir une - et de préférence une seule - manière évidente de le faire. .

127voto

nosklo Points 75862

Si vous devez attribuer le lambda à un nom, utilisez un def à la place. def ne sont que du sucre syntaxique pour une affectation, le résultat est donc le même, et ils sont beaucoup plus flexibles et lisibles.

lambda peuvent être utilisés pour à utiliser une fois, à jeter qui n'auront pas de nom.

Toutefois, ce cas d'utilisation est très rare. Vous avez rarement besoin de transmettre des objets de fonction sans nom.

Les builtins map() y filter() ont besoin d'objets fonctionnels, mais compréhensions de listes y expressions de générateur sont généralement plus lisibles que ces fonctions et peuvent couvrir tous les cas d'utilisation, sans avoir besoin de lambdas.

Pour les cas où vous avez vraiment besoin d'un petit objet de fonction, vous devriez utiliser la fonction operator les fonctions du module, comme operator.add au lieu de lambda x, y: x + y

Si vous avez encore besoin de lambda non couverte, vous pouvez envisager de rédiger une def juste pour être plus lisible. Si la fonction est plus complexe que celles à operator module, un def est probablement meilleure.

Donc, le monde réel est bon lambda Les cas d'utilisation sont très rares.

25 votes

Je suis d'accord avec la réponse pour savoir quand utiliser lambda mais je ne suis pas d'accord pour dire que c'est "très rare". sorted o itertools.groupby etc., par exemple sorted(['a1', 'b0'], key= lambda x: int(x[1]))

35voto

En pratique, pour moi, il y a deux différences :

La première concerne ce qu'ils font et ce qu'ils rapportent :

  • def est un mot-clé qui ne renvoie rien et crée un 'nom' dans l'espace de noms local.

  • lambda est un mot clé qui renvoie un objet fonction et ne crée pas de "nom" dans l'espace de nom local.

Par conséquent, si vous devez appeler une fonction qui prend un objet fonction, la seule façon de le faire en une ligne de code python est d'utiliser une lambda. Il n'y a pas d'équivalent avec def.

Dans certains frameworks, c'est en fait assez courant ; par exemple, j'utilise Torsadé beaucoup, et donc faire quelque chose comme

d.addCallback(lambda result: setattr(self, _someVariable, result))

est assez courante, et plus concise avec les lambdas.

La deuxième différence concerne ce que la fonction réelle est autorisée à faire.

  • Une fonction définie avec 'def' peut contenir n'importe quel code python.
  • Une fonction définie avec 'lambda' doit être évaluée par une expression, et ne peut donc pas contenir d'instructions comme print, import, raise, ...

Par exemple,

def p(x): print x

fonctionne comme prévu, tandis que

lambda x: print x

est une erreur de syntaxe.

Bien sûr, il y a des solutions de rechange - substitut print con sys.stdout.write o import con __import__ . Mais il est généralement préférable d'utiliser une fonction dans ce cas.

27voto

Chris Lawlor Points 10033

Dans cette interview, Guido van Rossum dit qu'il regrette de ne pas avoir introduit "lambda" dans Python :

" Q. Quelle est la caractéristique de Python dont vous êtes le moins satisfait ?

Il m'est arrivé d'accepter trop rapidement des contributions, et de me rendre compte plus tard que c'était une erreur. Lambda est un mot-clé qui vous permet de créer une petite fonction anonyme ; les fonctions intégrées telles que map, filter et reduce exécutent une fonction sur un type de séquence, comme une liste.

En pratique, cela ne s'est pas avéré si bien que cela. Python n'a que deux scopes : local et global. Cela rend l'écriture de fonctions lambda pénible, car on veut souvent accéder à des variables dans la portée où la lambda a été définie, mais on ne peut pas le faire à cause des deux portées. Il existe un moyen de contourner ce problème, mais il s'agit d'une sorte d'astuce. Souvent, il semble beaucoup plus facile en Python d'utiliser une boucle for plutôt que de s'embêter avec des fonctions lambda. map et ses amis ne fonctionnent bien que lorsqu'il existe déjà une fonction intégrée qui fait ce que vous voulez.

À mon avis, les Iambdas peuvent parfois être pratiques, mais ils le sont généralement au détriment de la lisibilité. Pouvez-vous me dire ce que cela fait ?

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

Je l'ai écrit, et ça m'a pris une minute pour le comprendre. Ceci est tiré du Projet Euler - je ne dirai pas quel problème parce que je déteste les spoilers, mais il s'exécute en 0,124 secondes :)

24 votes

Notez que l'interview est assez ancienne, et que Python a depuis longtemps ajouté les scopes imbriqués, ce qui rend l'argument qu'il donne contre lambda plus pertinent. Je suis sûr qu'il regrette toujours lambda, mais pas assez pour le supprimer dans Python 3.0.

14 votes

Vraiment votre exemple devrait être un argument contre les one-liners, pas les lambdas. De plus, vous auriez dû utiliser la fonction somme intégrée au lieu de réduire avec un lambda : str(sum(map(lambda x:x**x, range(1001))))[:-10]

2 votes

Thomas Wouters : Je comprends que lambda de ne pas être supprimé dans la 3.0 était une chose proche, et que Guido ne se battait pas pour le conserver.

12voto

Andy Hayden Points 38010

Pour n=1000, voici les temps d'appel d'une fonction par rapport à un lambda :

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop

5 votes

Il est intéressant de constater que les versions lambda et définie sont à peu près équivalentes. Le dernier test a pris plus de temps car python a probablement dû allouer de l'espace à chaque fois qu'il a défini cette fonction lambda.

0 votes

Je suppose que cela a du sens puisque la définition peut faire référence à des variables locales (qui peuvent avoir changé)... bien que dans le cas contraire, comme ici, cpython pourrait faire un meilleur travail.

1 votes

Utilisez dis.dis ; Votre (lambda x, y : x * y) crée la fonction chaque boucle. Si vous créez le lambda avant la boucle (aka f = lambda x, y : x * y), le bytecode pour appeler la fonction sera exactement le même que g/f dans votre exemple précédent, donc la performance du lambda est la même qu'une fonction def. Donc lambda ou def n'ont aucun impact si vous les utilisez de la même manière. Faites l'inverse, déclarez la fonction f() dans la boucle, puis appelez-la...

6voto

Dan Points 18831

Je suis d'accord avec le conseil de nosklo : si vous devez donner un nom à la fonction, utilisez def . Je me réserve lambda pour les cas où je ne fais que passer un bref extrait de code à une autre fonction, par exemple :

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )

3 votes

Dans la plupart des combinaisons map/lambda, vous pouvez la remplacer par une compréhension de liste ou une fonction plus appropriée. Par exemple, "map (sum, a)" ou "[x[0] + x[1] pour x dans a]".

0 votes

Oui, c'est vrai. Mais parfois, je préfère map(). C'était surtout un exemple artificiel d'utilisation d'une fonction en ligne.

0 votes

Exactement... La plupart des exemples sont inventés, car leur utilisation n'est pas naturelle et il existe de meilleures méthodes pratiques dans la plupart des cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X