Pourquoi les lambdas Python sont-ils utiles? [fermé]

929

J'essaie de comprendre les lambdas Python. Lambda fait-il partie de ces éléments de langage "intéressants" qui, dans la vraie vie, devraient être oubliés?

Je suis sûr qu'il y a des cas marginaux où cela pourrait être nécessaire, mais étant donné son obscurité, son potentiel d'être redéfini dans les versions futures (mon hypothèse basée sur les différentes définitions de celui-ci) et la clarté de codage réduite - si cela devait être évité?

Cela me rappelle le débordement (débordement de tampon) des types C - pointant vers la variable supérieure et surchargeant pour définir les autres valeurs de champ. Cela ressemble à une sorte de mise en scène technique, mais au cauchemar du codeur de maintenance.

meade
la source
261
+1 Bonne question - mauvaises hypothèses (obscurité de lambda) =) Essayez de ne pas porter de jugement sur les techniques de programmation. Évaluez-les et ajoutez-les à votre boîte à outils mentale. Si vous ne les aimez pas, ne les utilisez pas et préparez-vous à en discuter logiquement sans devenir religieux.
Kieveli
41
Règles Haskell! Les fonctions lambda vous offrent une puissance d'expressivité et d'abstraction.
Jonathan Barbero
11
@JAL Sans parler de LISP ...
ApproachingDarknessFish
8
@ApproachingDarknessFish "Ah, c'est la parenthèse de votre père. Une arme plus civilisée d'un âge plus civilisé." - Obi Lisp Kenobi
Fields du

Réponses:

1009

Parlez-vous des fonctions lambda ? Comme

lambda x: x**2 + 2*x - 5

Ces choses sont en fait très utiles. Python prend en charge un style de programmation appelé programmation fonctionnelle où vous pouvez passer des fonctions à d'autres fonctions pour faire des choses. Exemple:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

définit mult3à [3, 6, 9], les éléments de la liste d'origine qui sont des multiples de 3. Ceci est plus court (et, pourrait-on dire, plus clair) que

def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

Bien sûr, dans ce cas particulier, vous pouvez faire la même chose qu'une compréhension de liste:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(ou même comme range(3,10,3)), mais il existe de nombreux autres cas d'utilisation plus sophistiqués où vous ne pouvez pas utiliser une compréhension de liste et une fonction lambda peut être le moyen le plus court d'écrire quelque chose.

  • Retourner une fonction d'une autre fonction

    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    Ceci est souvent utilisé pour créer des wrappers de fonction, tels que les décorateurs de Python.

  • Combinaison d'éléments d'une séquence itérable avec reduce()

    >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • Tri par une clé alternative

    >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

J'utilise régulièrement des fonctions lambda. Il m'a fallu un certain temps pour m'y habituer, mais j'ai fini par comprendre qu'ils sont une partie très précieuse de la langue.

David Z
la source
26
J'adore les exemples, très faciles à comprendre. Mais pour la partie réduite. Si je dois implémenter cette fonctionnalité. Je ferais','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds
3
BTW si vous exécutez cela sur Python3, vous devez appeler la liste des résultats du filtre pour voir les valeurs réelles, vous devez également importer réduire à partir de functools
Gerard
Sommes-nous sûrs de la définition de "programmation fonctionnelle" ci-dessus? Cela m'a un peu dérouté.
stdout
3
Je pense que le point clé est que les lambdafonctions peuvent être anonymes (comme elles le sont dans tous vos exemples). Si vous attribuez une lambdafonction à quelque chose, vous le faites mal et def
devez
1
@zgulser Ce n'est pas une définition, c'est juste une déclaration sur quelque chose que la programmation fonctionnelle vous permet de faire.
David Z
377

lambdaest juste une façon élégante de dire function. À part son nom, il n'a rien d'obscur, d'intimidant ou de cryptique. Lorsque vous lisez la ligne suivante, remplacez lambdapar functiondans votre esprit:

>>> f = lambda x: x + 1
>>> f(3)
4

Il définit simplement une fonction de x. Certaines autres langues, comme R, le disent explicitement:

> f = function(x) { x + 1 }
> f(3)
4

Tu vois? C'est l'une des choses les plus naturelles à faire en programmation.

user251650
la source
36
Ceci est une excellente description pour ceux qui viennent d'horizons non-programmation (c'est-à-dire: sciences exactes) qui rend le sens de lambda très simple à comprendre. Merci!
Gabriel
10
Raymond Hettinger a déploré le nom dans l'un de ses entretiens et a déclaré que toute confusion aurait pu être évitée en le nommant «faire fonction» au lieu de «lambda». :-)
ankush981
10
remplacer lambdapar functiondans votre esprit et ajouter returnavant la dernière expression
Ciprian Tomoiagă
4
@AaronMcMillin Try type(lambda x: 3). lambdales expressions et les definstructions génèrent toutes deux des functionobjets; il est seulement la syntaxe d'une lambdaexpression que les limites qui les instances qu'elle peut produire.
chepner
6
@AaronMcMillin Vous manquez mon point. Ce n'est pas parce que vous ne pouvez pas définir chaque fonction avec une lambdaexpression que le résultat d'une lambdaexpression n'est pas une fonction.
chepner
107

Le résumé en deux lignes:

  1. Fermetures : très utile. Apprenez-les, utilisez-les, aimez-les.
  2. lambdaMot - clé de Python : inutile, parfois utile. Si vous vous retrouvez à faire quelque chose de complexe à distance avec lui, rangez-le et définissez une fonction réelle.
John Fouhy
la source
72

Un lambda fait partie d'un mécanisme d'abstraction très important qui traite des fonctions d'ordre supérieur. Pour bien comprendre sa valeur, veuillez regarder les leçons de haute qualité d' Abelson et Sussman et lire le livre SICP

Ce sont des questions pertinentes dans le secteur des logiciels modernes et qui deviennent de plus en plus populaires.

egaga
la source
1
Les expressions lambda deviennent également populaires dans d'autres langages (comme C #). Ils ne vont nulle part. La lecture des fermetures serait un exercice utile pour comprendre Lambdas. Les fermetures rendent possible beaucoup de magie de codage dans des frameworks comme jQuery.
Dan Esparza
3
Ne confondez pas lambdas et les fonctions de première classe. Python a une lambdainstruction extrêmement limitée , mais des fonctions entièrement de première classe. La seule différence que cela fait est que vous devez nommer les fonctions que vous souhaitez faire circuler.
Gareth Latty
59

les lambdas sont extrêmement utiles dans la programmation graphique. Par exemple, supposons que vous créez un groupe de boutons et que vous souhaitez utiliser un rappel unique paramétré plutôt qu'un rappel unique par bouton. Lambda vous permet d'accomplir cela facilement:

for value in ["one","two","three"]:
    b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
    b.pack()

(Remarque: bien que cette question porte spécifiquement sur lambda, vous pouvez également utiliser functools.partial pour obtenir le même type de résultat)

L'alternative consiste à créer un rappel distinct pour chaque bouton, ce qui peut entraîner un code dupliqué.

Bryan Oakley
la source
1
C'est exactement pourquoi j'ai recherché ce qu'était lambda, mais pourquoi cela fonctionne-t-il, pour moi, cela ressemble exactement à simplement appeler la fonction directement ( stackoverflow.com/questions/3704568/… ). Peut-être qu'il est tard, ça marche, mais pourquoi ça marche?
Rqomey
5
@Rqomey: la différence est que dans cet exemple valueest défini dans une boucle; dans l'autre exemple, le paramètre n'avait toujours qu'une seule valeur. Lorsque vous ajoutez quelque chose comme arg=value, vous attachez la valeur actuelle au rappel. Sans elle, vous liez une référence à la variable dans le rappel. La référence contiendra toujours la valeur finale de la variable, car le rappel se produit quelque temps après que la boucle a déjà terminé son exécution.
Bryan Oakley
1
Je viens de le faire fonctionner hier, honnêtement, je ne peux pas croire à quel point c'est utile ... Je peux créer un menu à partir d'un pour la boucle et d'un fichier csv pour la configuration. Des trucs vraiment utiles.
Rqomey
1
Notez l'existence functools.partial()qui vous permet de le faire avec moins de cruches (et sans lambda).
Gareth Latty
2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- le lambda a beaucoup plus de cruauté (affectation à arg et ensuite utilisation) et il est moins clair quelle est l'intention (vous pourriez faire quelque chose de subtilement différent dans le lambda). Les importations ne sont pas vraiment un problème (vous avez quand même une pile et c'est une fois par fichier). Le code est mieux jugé sur la qualité de sa lecture et partial()est beaucoup plus facile à lire que le lambda.
Gareth Latty
58

Je doute que lambda s'en ira. Voir le post de Guido sur l'abandon final de la tentative de suppression. Voir également un aperçu du conflit .

Vous pouvez consulter ce post pour plus d'historique sur l'accord derrière les fonctionnalités de Python: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

Curieusement, les fonctions de mappage, de filtrage et de réduction qui ont initialement motivé l'introduction de lambda et d'autres fonctionnalités ont été largement remplacées par des listes de compréhension et des expressions de générateur. En fait, la fonction de réduction a été supprimée de la liste des fonctions intégrées dans Python 3.0. (Cependant, il n'est pas nécessaire d'envoyer des plaintes concernant la suppression de lambda, de la carte ou du filtre: ils restent. :-)

Mes propres deux cents: Rarement lambda en vaut la peine en ce qui concerne la clarté. Il existe généralement une solution plus claire qui n'inclut pas lambda.

rhettg
la source
2
notez que la réduction est toujours importable dans Python 3.0. Si vous le voulez vraiment, vous pouvez toujours l'avoir.
Paweł Polewicz,
Je pense que la tentative de Guido était plus sur la syntaxe. Cette personne pense aussi que: cackhanded.com/blog/post/2008/01/24/…
leewz
38

En Python, lambdaest juste un moyen de définir des fonctions en ligne,

a = lambda x: x + 1
print a(1)

et..

def a(x): return x + 1
print a(1)

..sont exactement les mêmes.

Il n'y a rien que vous puissiez faire avec lambda que vous ne pouvez pas faire avec une fonction régulière - en Python, les fonctions sont un objet comme tout le reste, et lambdas définit simplement une fonction:

>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>

Je pense honnêtement que le lambdamot-clé est redondant en Python - je n'ai jamais eu besoin de les utiliser (ou vu une utilisée là où une fonction régulière, une compréhension de liste ou l'une des nombreuses fonctions intégrées aurait pu être mieux utilisée à la place)

Pour un exemple complètement aléatoire, extrait de l'article "Le lambda de Python est cassé!" :

Pour voir comment lambda est cassé, essayez de générer une liste de fonctions fs=[f0,...,f9]fi(n)=i+n. Premier essai:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13

Je dirais que même si cela a fonctionné, c'est horriblement et "impythonique", la même fonctionnalité pourrait être écrite de nombreuses autres façons, par exemple:

>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

Oui, ce n'est pas la même chose, mais je n'ai jamais vu de cause où la génération d'un groupe de fonctions lambda dans une liste a été requise. Cela pourrait avoir du sens dans d'autres langages, mais Python n'est pas Haskell (ou Lisp, ou ...)

Veuillez noter que nous pouvons utiliser lambda tout en obtenant les résultats souhaités de cette manière:

>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7

Éditer:

Il y a quelques cas où lambda est utile, par exemple, il est souvent pratique lors de la connexion de signaux dans des applications PyQt, comme ceci:

w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())

Le simple fait d' w.textChanged.connect(dothing)appeler la dothingméthode avec un eventargument supplémentaire et de provoquer une erreur. L'utilisation du lambda signifie que nous pouvons supprimer proprement l'argument sans avoir à définir une fonction de wrapping.

dbr
la source
2
votre argument "lambda est cassé" est cassé, car les règles de portée des variables python fonctionnent de cette façon, point. Vous serez mordu de la même manière si vous avez créé une fermeture à l'intérieur de for-loop.
Antti Haapala
1
lambda est juste la manière de python de fournir à l'utilisateur une fonction "anonyme", comme beaucoup d'autres langues (par exemple, javascript).
Stefan Gruenwald
1
Le lambda et la fonction aque vous avez définis ne sont pas exactement les mêmes. :) Ils diffèrent __name__au moins par domaine ...
nperson325681
1
Cela fonctionne plus qu'une simple fonction en ligne.
kta
Votre argument sur «pourrait avoir un sens dans une autre langue» est étrange. Soit il y a des qualités intrinsèques des lambdas, soit elles ne le sont pas.
Titou
31

Je trouve lambda utile pour une liste de fonctions qui font de même, mais pour des circonstances différentes.

Comme les règles plurielles de Mozilla :

plural_rules = [
    lambda n: 'all',
    lambda n: 'singular' if n == 1 else 'plural',
    lambda n: 'singular' if 0 <= n <= 1 else 'plural',
    ...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'

Si vous deviez définir une fonction pour tous ceux que vous deviendriez fous à la fin de celui-ci.
En outre, il ne serait pas bien avec les noms de fonctions comme plural_rule_1, plural_rule_2, etc. Et vous devez eval()quand vous êtes en fonction d'un identifiant de fonction variable.

Tor Valamo
la source
1
Cela ressemble aux brèves rencontres que j'ai eues jusqu'à présent en F # avec la correspondance de motifs et les options. Avez-vous plus d'informations sur l'utilisation de cette syntaxe?
Ken
26

À peu près tout ce que vous pouvez faire avec lambdavous pouvez faire mieux avec les fonctions nommées ou les expressions de liste et de générateur.

Par conséquent, pour la plupart, vous ne devriez en utiliser qu'une dans pratiquement toutes les situations (sauf peut-être pour le code de travail écrit dans l'interpréteur interactif).

Aaron Maenpaa
la source
3
"pour la plupart, vous ne devriez en utiliser qu'une dans pratiquement toutes les situations" Taper des lambda dans l'interpréteur n'est même pas très utile.
S.Lott
11
@Javier Je suis d'accord avec vous si vous parlez de "lambda" le concept; cependant, si nous parlons de "lambda" le mot-clé python alors: 1) les fonctions nommées sont plus rapides et peuvent faire plus (déclarations + expressions) presque partout où vous utiliseriez lambdas (carte + filtre), vous pouvez simplement générer des expressions ou des listes de compréhension qui sont plus performants et concis. Je ne dis pas que les fonctions de première classe ne sont pas cool, juste que le mot-clé "lambda" en python n'est pas aussi bon que d'utiliser simplement une fonction nommée, c'est tout.
Aaron Maenpaa
3
lambda m'a été indispensable pour une utilisation avec des fonctions qui prennent des arguments de rappel comme l'argument key = pour trier () et sorted ()
Rick Copeland
19
@Rick Je n'en doute pas, mais la réalité est que si vous voyez "lambda" et que vous pensez "zohmygod lambda" et commencez à écrire du code de schéma en python, vous serez sûrement déçu par les limites de l'expression lambda de python. D'un autre côté, si vous commencez à penser à vous-même "Est-ce qu'une compréhension de liste fonctionnera? Non. Ce dont j'ai besoin bénéficiera-t-il d'être une fonction nommée? Non. Très bien: trié (xs, clé = lambda x: x.name, x.height) ", vous finirez probablement par utiliser lambda le bon nombre de fois.
Aaron Maenpaa
4
+1: Je ne saurais trop insister sur le fait que lorsqu'on utilise un lambda, on utilise une fonction sans nom . Et les noms ont une valeur ajoutée intellectuelle précieuse .
Stephane Rolland
19

J'utilise Python depuis quelques années et je n'ai jamais rencontré de cas où j'avais besoin de lambda. Vraiment, comme le dit le tutoriel , c'est juste pour le sucre syntaxique.

Matt Schmidt
la source
8
Ils sont très utiles lors du développement d'une interface graphique à l'aide de python. Souvent, les widgets ont besoin d'une référence à une fonction. Si vous avez besoin d'un widget pour appeler une fonction et passer des arguments, lambda est un moyen très pratique de le faire.
Bryan Oakley
1
Quel est l'avantage de passer plusieurs arguments dans la fonction? func_name (a, b): retourne a + b plutôt que d'utiliser lambda
dter
2
ce n'est pas nécessaire, mais cela aide à écrire du code plus court et plus lisible dans de nombreux cas, en particulier. dans des langages verbeux comme Java ou C ++
phuclv
17

Je ne peux pas parler de l'implémentation particulière de lambda par python, mais en général les fonctions lambda sont vraiment pratiques. Ils sont une technique de base (peut-être même LA technique) de la programmation fonctionnelle, et ils sont également très utiles dans les programmes orientés objet. Pour certains types de problèmes, ils sont la meilleure solution, il ne faut donc pas les oublier!

Je vous suggère de lire les fermetures et la fonction de carte (qui relie aux documents python, mais elle existe dans presque tous les langages qui prennent en charge les constructions fonctionnelles) pour voir pourquoi elle est utile.

rmeador
la source
3
Ce truc peut être fait sans lambdas. C'est juste un gros tracas.
Brian
17

La fonction lambda est un moyen non bureaucratique de créer une fonction.

C'est ça. Par exemple, supposons que vous ayez votre fonction principale et que vous ayez besoin de mettre les valeurs au carré. Voyons la manière traditionnelle et la manière lambda de le faire:

Manière traditionnelle:

def main():
...
...
y = square(some_number)
...
return something

def square(x):
    return x**2

La façon lambda:

def main():
...
square = lambda x: x**2
y = square(some_number)
return something

Regarde la différence?

Les fonctions lambda vont très bien avec les listes, comme les compréhensions de listes ou les cartes. En fait, la compréhension des listes est une façon "pythonique" de vous exprimer en utilisant lambda. Ex:

>>>a = [1,2,3,4]
>>>[x**2 for x in a]
[1,4,9,16]

Voyons ce que signifie chaque élément de la syntaxe:

[]: "Donnez-moi une liste"

x ** 2: "en utilisant cette fonction nouveau-né"

pour x dans un: "dans chaque élément d'un"

C'est pratique euh? Créer des fonctions comme celle-ci. Réécrivons-le en utilisant lambda:

>>> square = lambda x: x**2
>>> [square(s) for x in a]
[1,4,9,16]

Maintenant, utilisons map, qui est la même chose, mais plus neutre en termes de langue. Maps prend 2 arguments:

(i) une fonction

(ii) un itérable

Et vous donne une liste où chaque élément est la fonction appliquée à chaque élément de l'itérable.

Donc, en utilisant la carte, nous aurions:

>>> a = [1,2,3,4]
>>> squared_list = map(lambda x: x**2, a)

Si vous maîtrisez les lambdas et la cartographie, vous aurez un grand pouvoir pour manipuler les données et de manière concise. Les fonctions lambda ne sont ni obscures ni nettes de la clarté du code. Ne confondez pas quelque chose de dur avec quelque chose de nouveau. Une fois que vous commencez à les utiliser, vous le trouverez très clair.

Lucas Ribeiro
la source
13

À lambdamon avis, une des bonnes choses sous-estimées est que c'est une façon de reporter une évaluation pour des formulaires simples jusqu'à ce que la valeur soit nécessaire. Laisse-moi expliquer.

De nombreuses routines de bibliothèque sont implémentées afin de permettre à certains paramètres d'être callables (dont lambda est un). L'idée est que la valeur réelle sera calculée uniquement au moment où elle va être utilisée (plutôt que lorsqu'elle est appelée). Un exemple (artificiel) pourrait aider à illustrer ce point. Supposons que vous ayez une routine qui allait enregistrer un horodatage donné. Vous voulez que la routine utilise l'heure actuelle moins 30 minutes. Tu appellerais ça comme ça

log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

Supposons maintenant que la fonction réelle ne sera appelée que lorsqu'un certain événement se produit et que vous souhaitez que l'horodatage soit calculé uniquement à ce moment. Vous pouvez faire ça comme ça

log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

En supposant que le log_timestamppeut gérer les callables comme celui-ci, il évaluera cela quand il en aura besoin et vous obtiendrez l'horodatage à ce moment-là.

Il y a bien sûr d'autres façons de le faire (en utilisant le operatormodule par exemple) mais j'espère avoir bien fait comprendre ce point.

Mise à jour : Voici un exemple un peu plus concret du monde réel.

Mise à jour 2 : Je pense que c'est un exemple de ce qu'on appelle un thunk .

Noufal Ibrahim
la source
11

Comme indiqué ci-dessus, l'opérateur lambda en Python définit une fonction anonyme, et dans les fonctions Python sont des fermetures. Il est important de ne pas confondre le concept de fermeture avec l'opérateur lambda, qui n'est pour eux que de la méthadone syntaxique.

Quand j'ai commencé en Python il y a quelques années, j'utilisais beaucoup les lambdas, pensant qu'ils étaient cool, ainsi que des listes de compréhension. Cependant, j'ai écrit et dois maintenir un gros site web écrit en Python, avec de l'ordre de plusieurs milliers de points de fonction. J'ai appris par expérience que les lambdas pourraient être corrects pour prototyper des choses, mais n'offrent rien sur les fonctions en ligne (fermetures nommées), sauf pour enregistrer quelques touches, ou parfois non.

Fondamentalement, cela se résume à plusieurs points:

  • il est plus facile de lire un logiciel écrit explicitement en utilisant des noms significatifs. Les fermetures anonymes par définition ne peuvent pas avoir de nom significatif, car elles n'ont pas de nom. Cette brièveté semble, pour une raison quelconque, infecter également les paramètres lambda, d'où nous voyons souvent des exemples comme lambda x: x + 1
  • il est plus facile de réutiliser les fermetures nommées, car elles peuvent être référencées plusieurs fois par leur nom, lorsqu'il existe un nom pour s'y référer.
  • il est plus facile de déboguer du code qui utilise des fermetures nommées au lieu de lambdas, car le nom apparaîtra dans les traces et autour de l'erreur.

C'est une raison suffisante pour les rassembler et les convertir en fermetures nommées. Cependant, je garde deux autres rancunes contre les fermetures anonymes.

La première rancune est simplement qu'ils ne sont qu'un autre mot clé inutile encombrant la langue.

La deuxième rancune est plus profonde et au niveau du paradigme, c'est-à-dire que je n'aime pas qu'ils promeuvent un style de programmation fonctionnelle, car ce style est moins flexible que le style de passage de message, orienté objet ou procédural, parce que le calcul lambda n'est pas Turing- complet (heureusement en Python, nous pouvons encore sortir de cette restriction même à l'intérieur d'un lambda). Les raisons pour lesquelles je pense que les lambdas font la promotion de ce style sont:

  • Il y a un retour implicite, c'est-à-dire qu'ils semblent "devoir" être des fonctions.

  • Ils sont un mécanisme alternatif de masquage d'état à un autre mécanisme, plus explicite, plus lisible, plus réutilisable et plus général: les méthodes.

Je m'efforce d'écrire du Python sans lambda et de supprimer les lambdas à vue. Je pense que Python serait un langage légèrement meilleur sans lambdas, mais c'est juste mon opinion.

Mike A
la source
1
"... en Python, les fonctions sont des fermetures". Ce n'est pas tout à fait vrai, si je comprends bien. Les fermetures sont des fonctions, mais les fonctions ne sont pas toujours des fermetures. Fonction-> lambda x, y: x + y. Fermeture-> lambda x: lambda y: x + y
0atman
6
"parce que le calcul lambda n'est pas Turing-complet" est tout à fait faux, le calcul lambda non typé EST Turing complet, c'est la raison pour laquelle il est si important. Vous pouvez obtenir une récursivité en utilisant le combinateur Y,Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Antti Haapala
En outre, si l'on se rend sur Wikipedia pour lire sur l'intégralité de Turing, il est écrit "Un exemple classique est le calcul lambda".
Antti Haapala
sérieusement - Pas Turing complet - cette réponse a besoin d'une révision ou d'une rétraction sérieuse.
Tony Suffolk 66
@ MarcinŁoś Voté parce qu'il adhère à KISS. À titre de comparaison, le livre K&R mentionne que, bien que l'utilisation de l'affectation en tant que partie ou une expression plus large soit plus compacte, elle est souvent moins lisible. La tendance à utiliser des modèles de programmation fonctionnels est banale et clichée. Il suffit d'indiquer comment ils peuvent être utilisés, mais il est exagéré de déclarer qu'ils sont primordiaux pour devenir un développeur compétent; complètement subjectif. Cet argument est analogue aux développeurs C ++ qui soutiennent que les langages sans classes sont primitifs, inférieurs et inadéquats. "Turing-compléteness", les arguments sont pédantes.
typedeaf
11

Les lambdas sont en fait des constructions très puissantes qui découlent des idées de programmation fonctionnelle, et c'est quelque chose qui ne sera en aucun cas facilement révisé, redéfini ou supprimé dans un proche avenir de Python. Ils vous aident à écrire du code plus puissant car il vous permet de passer des fonctions comme paramètres, d'où l'idée de fonctions en tant que citoyens de première classe.

Les lambdas ont tendance à être déroutants, mais une fois qu'une bonne compréhension est obtenue, vous pouvez écrire du code propre et élégant comme ceci:

squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

La ligne de code ci-dessus renvoie une liste des carrés des nombres dans la liste. Bien sûr, vous pouvez également le faire comme:

def square(x):
    return x*x

squared = map(square, [1, 2, 3, 4, 5])

Il est évident que l'ancien code est plus court, et cela est particulièrement vrai si vous avez l'intention d'utiliser la fonction de carte (ou toute fonction similaire qui prend une fonction comme paramètre) en un seul endroit. Cela rend également le code plus intuitif et élégant.

En outre, comme @David Zaslavsky l'a mentionné dans sa réponse, la compréhension des listes n'est pas toujours la voie à suivre, surtout si votre liste doit obtenir des valeurs d'une manière mathématique obscure.

D'un point de vue plus pratique, l'un des plus grands avantages des lambdas pour moi récemment a été la GUI et la programmation événementielle. Si vous regardez les rappels dans Tkinter, tout ce qu'ils prennent comme arguments est l'événement qui les a déclenchés. Par exemple

def define_bindings(widget):
    widget.bind("<Button-1>", do-something-cool)

def do-something-cool(event):
    #Your code to execute on the event trigger

Et si vous aviez des arguments à passer? Quelque chose d'aussi simple que de passer 2 arguments pour stocker les coordonnées d'un clic de souris. Vous pouvez facilement le faire comme ceci:

def main():
    # define widgets and other imp stuff
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do-something-cool(x, y))

def do-something-cool(event, x, y):
    x = event.x
    y = event.y
    #Do other cool stuff

Vous pouvez maintenant affirmer que cela peut être fait à l'aide de variables globales, mais voulez-vous vraiment vous cogner la tête en vous inquiétant de la gestion de la mémoire et des fuites, surtout si la variable globale ne sera utilisée qu'à un endroit particulier? Ce serait juste un mauvais style de programmation.

En bref, les lambdas sont géniaux et ne devraient jamais être sous-estimés. Les lambdas Python ne sont pas les mêmes que les lambdas LISP (qui sont plus puissants), mais vous pouvez vraiment faire beaucoup de choses magiques avec eux.

varagrawal
la source
Merci. Je n'ai pas du tout compris votre dernier exemple. Comment se fait-il que x et y soient définis à la fois dans mainet do_something_cool? Qu'arrive-t-il à xet ydans la fonction? Les valeurs transmises semblent être immédiatement écrasées? Comment la fonction est-elle informée event? Pourriez-vous ajouter quelques commentaires / explications? Merci
Sanjay Manohar
@SanjayManohar Je passe xet ycomme arguments à do-something-coolet leurs valeurs sont définies dans la fonction pour illustrer comment vous pouvez utiliser lambdas pour passer des arguments là où aucun n'est attendu. La widget.bindfonction attend un eventparamètre qui identifie l'événement GUI sur ce widget particulier. Je recommande de lire sur le modèle de programmation de Tkinter pour plus de clarté.
varagrawal
hmm je pense que je comprends le modèle Tkinter. Mais je ne comprends toujours pas tout à fait - vous passez x,yalors faites x=event.x. Cela n'écrase-t-il pas la valeur que vous avez transmise? Et comment la fonction sait-elle ce qu'est event? Je ne vois pas où vous passez cela à la fonction. Ou est-ce une méthode? Êtes-vous également autorisé à utiliser les signes moins dans un nom de fonction?
Sanjay Manohar
@SanjayManohar copain, vous devez lire sur Tkinter et Python. Tkinter transmet l'objet événement la fonction comme une action par défaut. Quant à la x, y, ce n'est qu'un exemple à des fins d'illustration. J'essaie de montrer le pouvoir des lambdas, pas de Tkinter. :)
varagrawal
1
OK maintenant je vois ce que vous vouliez - vous voulez que la fonction reçoive event? dans ce cas, votre lambda ne devrait-il pas lire lambda event: do_something_cool(event,x,y)?
Sanjay Manohar
8

Les lambdas sont profondément liés au style de programmation fonctionnel en général. L'idée que vous pouvez résoudre des problèmes en appliquant une fonction à certaines données et en fusionnant les résultats, est ce que Google utilise pour implémenter la plupart de ses algorithmes.

Les programmes écrits dans un style de programmation fonctionnel sont facilement parallélisés et deviennent donc de plus en plus importants avec les machines multicœurs modernes. Donc en bref, NON, vous ne devez pas les oublier.

Yogi
la source
7

Premiers félicitations qui ont réussi à comprendre lambda. À mon avis, c'est une construction vraiment puissante pour agir avec. La tendance actuelle vers les langages de programmation fonctionnels est certainement un indicateur qu'il ne faut ni l'éviter ni le redéfinir dans un avenir proche.

Il suffit de penser un peu différemment. Je suis sûr que vous allez bientôt l'adorer. Mais soyez prudent si vous ne traitez qu'avec python. Parce que le lambda n'est pas une vraie fermeture, il est "cassé" en quelque sorte: les pythons lambda sont cassés

Norbert Hartl
la source
Le lambda de Python n'est pas cassé. Il existe deux façons de gérer les habitants de lambdas. Les deux ont des avantages et des inconvénients. Je pense que l'approche adoptée par Python (et C #) est probablement contre-intuitive pour ceux qui sont plus habitués aux langages purement fonctionnels, car avec un langage purement fonctionnel, je ne pense pas que cette approche ait même un sens.
Brian
C'est en effet contre-intuitif. Je ne suis pas un programmeur Python, mais dans Squeak Smalltalk, c'est la même chose et je tombe régulièrement dessus. Donc, même je le considérerais "cassé" :)
Norbert Hartl
Non, cela n'a rien à voir avec la contre-intuitivité. C'est juste que la portée lexicale des noms de variables est celle d'une fonction; une boucle n'introduit pas de portée lexicale. Les fonctions fonctionnent également de la même manière en Javascript. Si vous avez besoin d'une étendue pour var, vous pouvez toujours le faire (lambda scopedvar: lambda x: scopedvar + x) ()
Antti Haapala
6

Je viens de commencer Python et j'ai couru la tête la première dans Lambda - ce qui m'a pris un certain temps pour comprendre.

Notez que ce n'est pas une condamnation de quoi que ce soit. Tout le monde a un ensemble différent de choses qui ne viennent pas facilement.

Lambda est-il un de ces éléments de langage «intéressants» qui, dans la vraie vie, devraient être oubliés?

Non.

Je suis sûr qu'il y a des cas marginaux où cela pourrait être nécessaire, mais étant donné son obscurité,

Ce n'est pas obscur. Les 2 dernières équipes sur lesquelles j'ai travaillé, tout le monde a utilisé cette fonctionnalité tout le temps.

le potentiel de celui-ci étant redéfini dans les versions futures (mon hypothèse basée sur les différentes définitions de celui-ci)

Je n'ai vu aucune proposition sérieuse pour le redéfinir en Python, à part corriger la sémantique de fermeture il y a quelques années.

et la clarté de codage réduite - faut-il l'éviter?

Ce n'est pas moins clair, si vous l'utilisez correctement. Au contraire, avoir plus de constructions de langage disponibles augmente la clarté.

Cela me rappelle le débordement (débordement de tampon) des types C - pointant vers la variable supérieure et surchargeant pour définir les autres valeurs de champ ...

Lambda est comme un débordement de tampon? Sensationnel. Je ne peux pas imaginer comment vous utilisez lambda si vous pensez que c'est un "cauchemar de maintenance".

Ken
la source
5
-1 pour m'avoir fait (ainsi que d'autres) relire toute la question. Notez que d'autres ont réussi à répondre sans le faire.
Paweł Polewicz
6

J'utilise des lambdas pour éviter la duplication de code. Cela rendrait la fonction facilement compréhensible. Par exemple:

def a_func()
  ...
  if some_conditon:
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)
  else
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)

Je remplace ça par un lambda temp

def a_func()
  ...
  call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
  if some_conditon:
     ...
     call_big_f(argX)
  else
     ...
     call_big_f(argY)
balki
la source
5

J'ai commencé à lire le livre de David Mertz aujourd'hui «Text Processing in Python». Bien qu'il ait une description assez concise de Lambda, les exemples du premier chapitre combinés à l'explication de l'annexe A les ont fait sauter la page pour moi (enfin) et tout d'un coup j'ai compris leur valeur. Cela ne veut pas dire que son explication fonctionnera pour vous et je suis encore au stade de la découverte, donc je n'essaierai pas d'ajouter à ces réponses autres que les suivantes: je suis nouveau sur Python je suis nouveau sur OOP Lambdas était une lutte pour moi Maintenant que j'ai lu Mertz, je pense que je les ai et je les vois aussi très utiles que je pense qu'ils permettent une approche plus propre de la programmation.

Il reproduit le Zen of Python, dont une ligne est simple, c'est mieux que complexe. En tant que programmeur non-OOP lisant du code avec lambdas (et jusqu'à la semaine dernière, liste des compréhensions), j'ai pensé: c'est simple? . J'ai finalement réalisé aujourd'hui que ces fonctionnalités rendent le code beaucoup plus lisible et compréhensible que l'alternative, qui est invariablement une boucle. J'ai également réalisé que, comme les états financiers, Python n'était pas conçu pour l'utilisateur novice, mais plutôt pour l'utilisateur qui veut s'instruire. Je ne peux pas croire à quel point ce langage est puissant. Quand j'ai compris (enfin) le but et la valeur des lambdas, j'ai voulu déchirer environ 30 programmes et recommencer à mettre des lambdas le cas échéant.

PyNEwbie
la source
5

Un cas utile pour l'utilisation de lambdas est d' améliorer la lisibilité des compréhensions de longue liste . Dans cet exemple, loop_dicc'est court pour la clarté, mais imaginez loop_dicêtre très long. Si vous utilisiez simplement une valeur simple qui inclut iau lieu de la version lambda de cette valeur, vous obtiendrez un NameError.

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

Au lieu de

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]
Bentley4
la source
5

Je peux vous donner un exemple où j'avais réellement besoin de lambda sérieux. Je fais un programme graphique, où l'utilisation clique avec le bouton droit sur un fichier et lui attribue l'une des trois options. Il s'avère que dans Tkinter (le programme d'interface GUI dans lequel j'écris ceci), lorsque quelqu'un appuie sur un bouton, il ne peut pas être affecté à une commande qui accepte des arguments. Donc, si j'ai choisi l'une des options et que je voulais que le résultat de mon choix soit:

print 'hi there'

Alors ce n'est pas grave. Mais si j'ai besoin de mon choix pour avoir un détail particulier. Par exemple, si je choisis le choix A, il appelle une fonction qui accepte un argument qui dépend du choix A, B ou C, TKinter ne pourrait pas le prendre en charge. Lamda était la seule option pour contourner cela en fait ...

Glueberg
la source
2
Eh bien, je suppose que vous auriez pu le faire def foo..., puis être passé à la fooplace de lambda. C'est juste plus de code et vous devez trouver un nom.
Jon Coombs
4

Je l'utilise assez souvent, principalement comme objet nul ou pour lier partiellement des paramètres à une fonction.

Voici quelques exemples:

pour implémenter un modèle d'objet nul:

{
    DATA_PACKET: self.handle_data_packets
    NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)

pour la liaison de paramètres:

disons que j'ai l'API suivante

def dump_hex(file, var)
    # some code
    pass

class X(object):
    #...
    def packet_received(data):
        # some kind of preprocessing
        self.callback(data)
    #...

Ensuite, quand je ne veux pas vider rapidement les données reçues dans un fichier, je le fais:

dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()
Piotr Czapla
la source
4

j'utilise lambda pour créer des rappels qui incluent des paramètres. Il est plus simple d'écrire un lambda sur une seule ligne que d'écrire une méthode pour effectuer la même fonctionnalité.

Par exemple:

import imported.module

def func():
    return lambda: imported.module.method("foo", "bar")

par opposition à:

import imported.module

def func():
    def cb():
        return imported.module.method("foo", "bar")
    return cb
NuclearPeon
la source
4

Je suis un débutant en python, donc pour avoir une idée claire de lambda, je l'ai comparé avec une boucle 'for'; en termes d'efficacité. Voici le code (python 2.7) -

import time
start = time.time() # Measure the time taken for execution

def first():
    squares = map(lambda x: x**2, range(10))
    # ^ Lambda
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0 seconds

def second():
    lst = []
    for i in range(10):
        lst.append(i**2)
    # ^ a 'for' loop
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0019998550415 seconds.

print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)
Pratik Kulkarni
la source
6
Vous pouvez être intéressé par le timeitmodule, qui donne généralement des résultats plus précis que la soustraction de time.time()valeurs.
Kevin
2
Hmm, n'avez-vous pas besoin de redémarrer votre chronomètre au début des premier () et second ()?
qneill
2

Lambda est un constructeur de procédures. Vous pouvez synthétiser des programmes au moment de l'exécution, bien que le lambda de Python ne soit pas très puissant. Notez que peu de gens comprennent ce type de programmation.

Nick Dandoulakis
la source