Warum sind Python-Lambdas nützlich? [geschlossen]

929

Ich versuche Python Lambdas herauszufinden. Ist Lambda eines dieser "interessanten" Sprachelemente, die im wirklichen Leben vergessen werden sollten?

Ich bin mir sicher, dass es einige Randfälle gibt, in denen dies erforderlich sein könnte, aber angesichts der Unklarheit, des Potenzials einer Neudefinition in zukünftigen Versionen (meine Annahme basiert auf den verschiedenen Definitionen) und der verringerten Klarheit der Codierung - sollte dies der Fall sein Gemieden werden?

Dies erinnert mich an ein Überlaufen (Pufferüberlauf) von C-Typen - Zeigen auf die oberste Variable und Überladen, um die anderen Feldwerte festzulegen. Es fühlt sich an wie eine Art Technikfreak, aber ein Alptraum für Wartungscodierer.

meade
quelle
261
+1 Gute Frage - schlechte Annahmen (Dunkelheit von Lambda) =) Versuchen Sie, Programmiertechniken nicht zu beurteilen. Bewerten Sie sie und fügen Sie sie Ihrem mentalen Toolkit hinzu. Wenn Sie sie nicht mögen, verwenden Sie sie nicht und seien Sie bereit, sie logisch zu diskutieren, ohne religiös zu werden.
Kieveli
41
Haskell Regeln! Lambda-Funktionen verleihen Ihnen Ausdruckskraft und Abstraktionskraft.
Jonathan Barbero
11
@ JAL Ganz zu schweigen von LISP ...
ApproachingDarknessFish
8
@ApproachingDarknessFish "Ah, das ist die Klammer deines Vaters. Eine zivilisiertere Waffe aus einem zivilisierteren Alter." - Obi Lisp Kenobi
Fields

Antworten:

1009

Sprechen Sie über Lambda-Funktionen ? Mögen

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

Diese Dinge sind eigentlich sehr nützlich. Python unterstützt einen Programmierstil namens funktionale Programmierung, bei dem Sie Funktionen an andere Funktionen übergeben können, um Aufgaben zu erledigen. Beispiel:

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

setzt mult3auf [3, 6, 9]die Elemente der ursprünglichen Liste, die ein Vielfaches von 3 sind. Dies ist kürzer (und, wie man argumentieren könnte, klarer) als

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

In diesem speziellen Fall können Sie natürlich dasselbe tun wie ein Listenverständnis:

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

(oder sogar als range(3,10,3)), aber es gibt viele andere, komplexere Anwendungsfälle, in denen Sie kein Listenverständnis verwenden können und eine Lambda-Funktion möglicherweise der kürzeste Weg ist, etwas aufzuschreiben.

  • Rückgabe einer Funktion von einer anderen Funktion

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

    Dies wird häufig verwendet, um Funktionsumbrüche wie Pythons Dekoratoren zu erstellen.

  • Kombinieren von Elementen einer iterierbaren Sequenz mit 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'
  • Sortieren nach einem alternativen Schlüssel

    >>> 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]

Ich benutze regelmäßig Lambda-Funktionen. Es dauerte eine Weile, bis ich mich an sie gewöhnt hatte, aber irgendwann wurde mir klar, dass sie ein sehr wertvoller Teil der Sprache sind.

David Z.
quelle
26
Ich liebe die Beispiele, sehr leicht zu verstehen. Aber für den reduzierten Teil. Wenn ich diese Funktion implementieren muss. Ich würde tun','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds
3
Übrigens, wenn Sie dies auf Python3 ausführen, müssen Sie die Liste der Filterergebnisse aufrufen, um die tatsächlichen Werte anzuzeigen. Außerdem müssen Sie Reduce aus Funktools importieren
Gerard,
Sind wir uns über die Definition von "funktionaler Programmierung" oben sicher? Es kam mir ein bisschen verwirrend vor.
Stdout
3
Ich denke, der entscheidende Punkt ist, dass lambdaFunktionen anonym sein können (wie in all Ihren Beispielen). Wenn Sie lambdairgendetwas eine Funktion zuweisen , dann machen Sie es falsch und sollten defstattdessen verwenden
Chris_Rands
1
@zgulser Es ist keine Definition, es ist nur eine Aussage über etwas, das Sie mit funktionaler Programmierung tun können.
David Z
377

lambdaist nur eine ausgefallene Art zu sagen function. Abgesehen von seinem Namen ist nichts Unbekanntes, Einschüchterndes oder Kryptisches daran. Wenn Sie die folgende Zeile zu lesen, ersetzen lambdadurch functionim Kopf:

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

Es definiert nur eine Funktion von x. Einige andere Sprachen Rsagen es ausdrücklich:

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

Siehst du? Es ist eines der natürlichsten Dinge beim Programmieren.

user251650
quelle
36
Dies ist eine großartige Beschreibung für Personen mit nicht programmiertem Hintergrund (dh exakten Wissenschaften), wodurch die Bedeutung von lambda sehr einfach zu verstehen ist. Vielen Dank!
Gabriel
10
Raymond Hettinger beklagte den Namen in einem seiner Vorträge und sagte, dass jede Verwirrung hätte vermieden werden können, wenn man ihn "make function" anstelle von "lambda" nannte. :-)
ankush981
10
Ersetzen Sie lambdadurch functionin Ihrem Kopf und fügen Sie returnvor dem letzten Ausdruck hinzu
Ciprian Tomoiagă
4
@ AaronMcMillin versuchen type(lambda x: 3). lambdaAusdrücke und defAnweisungen erzeugen beide functionObjekte; Nur die Syntax eines lambdaAusdrucks begrenzt, welche Instanzen er erzeugen kann.
Chepner
6
@ AaronMcMillin Du vermisst meinen Standpunkt. Nur weil Sie nicht jede Funktion mit einem lambdaAusdruck definieren können, heißt das nicht, dass das Ergebnis eines lambdaAusdrucks keine Funktion ist.
Chepper
107

Die zweizeilige Zusammenfassung:

  1. Verschlüsse : Sehr nützlich. Lerne sie, benutze sie, liebe sie.
  2. Pythons lambdaSchlüsselwort: unnötig, gelegentlich nützlich. Wenn Sie feststellen, dass Sie etwas entfernt Komplexes damit tun, legen Sie es weg und definieren Sie eine echte Funktion.
John Fouhy
quelle
72

Ein Lambda ist Teil eines sehr wichtigen Abstraktionsmechanismus, der sich mit Funktionen höherer Ordnung befasst. Um den Wert richtig zu verstehen, schauen Sie sich bitte hochwertige Lektionen von Abelson und Sussman an und lesen Sie das Buch SICP

Dies sind relevante Themen im modernen Softwaregeschäft, die immer beliebter werden.

egaga
quelle
1
Lambda-Ausdrücke werden auch in anderen Sprachen (wie C #) immer beliebter. Sie gehen nirgendwo hin. Das Nachlesen von Schließungen wäre eine nützliche Übung, um Lambdas zu verstehen. Verschlüsse ermöglichen viel Codierungsmagie in Frameworks wie jQuery.
Dan Esparza
3
Verwechseln Sie nicht lambdas und erstklassige Funktionen. Python hat eine extrem eingeschränkte lambdaAussage, aber völlig erstklassige Funktionen. Der einzige Unterschied besteht darin, dass Sie die Funktionen benennen müssen, die Sie weitergeben möchten.
Gareth Latty
59

Lambdas sind äußerst nützlich bei der GUI-Programmierung. Angenommen, Sie erstellen eine Gruppe von Schaltflächen und möchten einen einzelnen parametrisierten Rückruf anstelle eines eindeutigen Rückrufs pro Schaltfläche verwenden. Mit Lambda können Sie dies mühelos erreichen:

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

(Hinweis: Obwohl diese Frage speziell gestellt wird lambda, können Sie auch functools.partial verwenden , um den gleichen Ergebnistyp zu erhalten.)

Die Alternative besteht darin, für jede Schaltfläche einen separaten Rückruf zu erstellen, der zu doppeltem Code führen kann.

Bryan Oakley
quelle
1
Genau aus diesem Grund habe ich nachgeschlagen, was Lambda war, aber warum funktioniert das ? Für mich sieht es genauso aus, als würde ich die Funktion direkt aufrufen ( stackoverflow.com/questions/3704568/… ). Vielleicht ist es spät, es funktioniert, aber warum funktioniert es?
Rqomey
5
@Rqomey: Der Unterschied besteht darin, dass in diesem Beispiel valueeine Schleife definiert ist. im anderen Beispiel hatte der Parameter immer nur einen Wert. Wenn Sie so etwas wie hinzufügen, fügen arg=valueSie dem Rückruf den aktuellen Wert hinzu. Ohne sie binden Sie einen Verweis auf die Variable im Rückruf. Die Referenz enthält immer den Endwert der Variablen, da der Rückruf einige Zeit nach Beendigung der Schleife erfolgt.
Bryan Oakley
1
Ich habe das erst gestern zum Laufen gebracht, ich kann ehrlich gesagt nicht glauben, wie nützlich es ist ... Ich kann ein Menü aus einem for-Loop und einer CSV-Datei für die Konfiguration erstellen. Wirklich nützliches Zeug.
Rqomey
1
Beachten functools.partial()Sie, dass Sie dies mit weniger Cruft (und ohne lambda) tun können .
Gareth Latty
2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- das Lambda hat viel mehr Cruft (Zuordnung zu Arg und dann Verwendung) und es ist weniger klar, was die Absicht ist (Sie könnten etwas subtil anderes im Lambda tun). Importe sind eigentlich kein Problem (Sie haben sowieso einen Stapel und es ist einmal pro Datei). Code lässt sich am besten daran messen, wie gut er liest, und partial()ist viel einfacher zu lesen als das Lambda.
Gareth Latty
58

Ich bezweifle, dass Lambda verschwinden wird. Siehe Guidos Beitrag über das endgültige Aufgeben des Versuchs, ihn zu entfernen. Sehen Sie sich auch einen Überblick über den Konflikt an .

In diesem Beitrag erfahren Sie mehr über die Funktionsweise von Python: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

Seltsamerweise wurden die Funktionen zum Zuordnen, Filtern und Reduzieren, die ursprünglich zur Einführung von Lambda und anderen Funktionsmerkmalen geführt haben, weitgehend durch Listenverständnisse und Generatorausdrücke ersetzt. Tatsächlich wurde die Reduzierungsfunktion aus der Liste der in Python 3.0 integrierten Funktionen entfernt. (Es ist jedoch nicht erforderlich, Beschwerden über die Entfernung von Lambda, Karte oder Filter einzureichen: Sie bleiben. :-)

Meine eigenen zwei Cent: Selten ist Lambda es wert, was die Klarheit betrifft. Im Allgemeinen gibt es eine klarere Lösung, die kein Lambda enthält.

Rhettg
quelle
2
Beachten Sie, dass Reduzieren in Python 3.0 weiterhin importierbar ist. Wenn Sie es wirklich wollen, können Sie es immer noch haben.
Paweł Polewicz
Ich denke, Guidos Versuch war mehr über die Syntax. Diese Person denkt auch, dass: cackhanded.com/blog/post/2008/01/24/…
leewz
38

In Python lambdaist dies nur eine Möglichkeit, Funktionen inline zu definieren.

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

und..

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

..sind das genaue gleiche.

Mit Lambda können Sie nichts tun, was Sie mit einer regulären Funktion nicht tun können. In Python sind Funktionen ein Objekt wie alles andere, und Lambdas definieren einfach eine Funktion:

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

Ich denke ehrlich das lambda Schlüsselwort in Python überflüssig ist - ich hatte nie die Notwendigkeit, sie zu verwenden (oder habe eine gesehen, bei der eine reguläre Funktion, ein Listenverständnis oder eine der vielen integrierten Funktionen besser hätte verwendet werden können).

Für ein völlig zufälliges Beispiel aus dem Artikel "Pythons Lambda ist kaputt!" ::

Um zu sehen, wie Lambda kaputt ist, erstellen Sie eine Liste mit Funktionen, bei fs=[f0,...,f9]denen fi(n)=i+n. Erster Versuch:

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

Ich würde argumentieren, auch wenn das funktioniert hat, es ist schrecklich und "unpythonisch", die gleiche Funktionalität könnte auf unzählige andere Arten geschrieben werden, zum Beispiel:

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

Ja, es ist nicht dasselbe, aber ich habe noch nie eine Ursache gesehen, bei der das Generieren einer Gruppe von Lambda-Funktionen in einer Liste erforderlich war. In anderen Sprachen mag es sinnvoll sein, aber Python ist nicht Haskell (oder Lisp oder ...)

Bitte beachten Sie, dass wir Lambda verwenden und dennoch die gewünschten Ergebnisse auf folgende Weise erzielen können:

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

Bearbeiten:

Es gibt einige Fälle, in denen Lambda nützlich ist. Beispielsweise ist es häufig praktisch, wenn Signale in PyQt-Anwendungen wie folgt angeschlossen werden:

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

Nur dies w.textChanged.connect(dothing)würde die dothingMethode mit einem zusätzlichen eventArgument aufrufen und einen Fehler verursachen. Die Verwendung des Lambda bedeutet, dass wir das Argument ordentlich löschen können, ohne eine Umhüllungsfunktion definieren zu müssen.

dbr
quelle
2
Ihr Argument "Lambda ist kaputt" ist kaputt, da die Regeln für das Scoping von Python-Variablen auf diese Weise funktionieren. Sie werden auf die gleiche Weise gebissen, wenn Sie einen Verschluss innerhalb der for-Schleife erstellt haben.
Antti Haapala
1
Lambda ist nur Pythons Weg, um dem Benutzer eine "anonyme" Funktion zu bieten, wie es viele andere Sprachen haben (z. B. Javascript).
Stefan Gruenwald
1
Das von aIhnen definierte Lambda und die Funktion sind nicht genau gleich. :) Sie unterscheiden sich __name__mindestens nach Feld ...
nperson325681
1
Es funktioniert mehr als nur eine Inline-Funktion.
KTA
Ihr Argument über "könnte in einer anderen Sprache Sinn machen" ist seltsam. Entweder gibt es intrinsische Eigenschaften von Lambdas oder sie sind es nicht.
Titou
31

Ich finde Lambda nützlich für eine Liste von Funktionen, die dasselbe tun, aber für unterschiedliche Umstände.

Wie die Mozilla-Pluralregeln :

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'

Wenn Sie eine Funktion für alle definieren müssten, würden Sie am Ende verrückt werden.
Auch wäre es nicht schön , mit Funktionsnamen wie sein plural_rule_1, plural_rule_2etc. Und Sie würden brauchen eval()es , wenn Sie auf eine Variable Funktion id sind abhängig.

Tor Valamo
quelle
1
Dies ähnelt den kurzen Begegnungen, die ich bisher in F # mit Mustervergleich und Optionen hatte. Haben Sie weitere Informationen zur Verwendung dieser Syntax?
Ken
26

So ziemlich alles, was Sie damit machen können lambda, können Sie entweder mit benannten Funktionen oder mit Listen- und Generatorausdrücken besser machen.

Folglich sollten Sie zum größten Teil nur eine davon in praktisch jeder Situation verwenden (außer vielleicht für den im interaktiven Interpreter geschriebenen Scratch-Code).

Aaron Maenpaa
quelle
3
"Zum größten Teil sollten Sie nur eine davon in praktisch jeder Situation" Zeitraum. Das Eingeben von Lambdas in den Dolmetscher ist nicht einmal so hilfreich.
S.Lott
11
@ Javier Ich stimme Ihnen zu, wenn Sie über "Lambda" das Konzept sprechen; Wenn wir jedoch über "lambda", das Python-Schlüsselwort, sprechen, dann: 1) benannte Funktionen sind schneller und können mehr (Anweisungen + Ausdrücke) fast überall dort ausführen, wo Sie Lambdas verwenden würden (Map + Filter). Sie können nur Ausdrücke generieren oder Verständnis auflisten die sind performanter und prägnanter. Ich sage nicht, dass erstklassige Funktionen nicht cool sind, nur dass das Schlüsselwort "Lambda" in Python nicht so gut ist wie die Verwendung einer benannten Funktion, das ist alles.
Aaron Maenpaa
3
Lambda war für mich unverzichtbar für die Verwendung mit Funktionen, die Rückrufargumente wie das Argument key = to sort () und sorted () verwenden
Rick Copeland
19
@ Rick Ich bezweifle das nicht, aber die Realität ist, wenn Sie "Lambda" sehen und "zohmygod lambda" denken und anfangen, Schema-Code in Python zu schreiben, werden Sie sicherlich von den Einschränkungen des Lambda-Ausdrucks von Python enttäuscht sein. Auf der anderen Seite, wenn Sie anfangen, sich selbst zu überlegen: "Funktioniert ein Listenverständnis? Nein. Wird das, was ich brauche, von einer benannten Funktion profitieren? Nein. Okay, gut: sortiert (xs, key = lambda x: x.name, x.height) ", werden Sie wahrscheinlich Lambda die richtige Anzahl von Malen verwenden.
Aaron Maenpaa
4
+1: Ich kann nicht genug betonen, wenn man ein Lambda benutzt, verwendet man eine namenlose Funktion. Und Namen haben einen wertvollen intellektuellen Mehrwert.
Stephane Rolland
19

Ich benutze Python seit ein paar Jahren und bin noch nie auf einen Fall gestoßen, in dem ich Lambda brauchte . Wirklich, wie das Tutorial sagt, ist es nur für syntaktischen Zucker.

Matt Schmidt
quelle
8
Sie sind sehr nützlich, wenn Sie eine GUI mit Python entwickeln. Widgets benötigen häufig einen Verweis auf eine Funktion. Wenn Sie ein Widget benötigen, um eine Funktion aufzurufen und Argumente zu übergeben, ist Lambda eine sehr bequeme Möglichkeit, dies zu tun.
Bryan Oakley
1
Was ist der Vorteil gegenüber der Übergabe mehrerer Argumente an die Funktion? func_name (a, b): a + b zurückgeben anstatt lambda
dter
2
es wird nicht benötigt, aber es hilft, kürzeren Code zu schreiben und in vielen Fällen besser lesbar zu sein, insb. in ausführlichen Sprachen wie Java oder C ++
phuclv
17

Ich kann nicht mit Pythons spezieller Implementierung von Lambda sprechen, aber im Allgemeinen sind Lambda-Funktionen sehr praktisch. Sie sind eine Kerntechnik (vielleicht sogar DIE Technik) der funktionalen Programmierung und sie sind auch in objektorientierten Programmen sehr nützlich. Für bestimmte Arten von Problemen sind sie die beste Lösung, sollten Sie also auf keinen Fall vergessen!

Ich schlage vor, Sie informieren sich über Abschlüsse und die Map-Funktion (die auf Python-Dokumente verweist, aber in fast jeder Sprache vorhanden ist, die funktionale Konstrukte unterstützt), um herauszufinden, warum sie nützlich ist.

rmeador
quelle
3
Das Zeug kann ohne Lambdas gemacht werden. Es ist nur ein großer Ärger.
Brian
17

Die Lambda-Funktion ist eine unbürokratische Methode zum Erstellen einer Funktion.

Das ist es. Nehmen wir zum Beispiel an, Sie haben Ihre Hauptfunktion und müssen Werte quadrieren. Sehen wir uns den traditionellen Weg und den Lambda-Weg an, um dies zu tun:

Traditioneller Weg:

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

def square(x):
    return x**2

Der Lambda-Weg:

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

Sieh den Unterschied?

Lambda-Funktionen passen sehr gut zu Listen wie Listenverständnis oder Karte. Listenverständnis ist in der Tat eine "pythonische" Art, sich mit Lambda auszudrücken. Ex:

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

Mal sehen, was jedes Element der Syntax bedeutet:

[]: "Gib mir eine Liste"

x ** 2: "Verwenden dieser neugeborenen Funktion"

für x in a: "in jedes Element in a"

Das ist praktisch, oder? Funktionen wie diese erstellen. Schreiben wir es mit Lambda um:

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

Verwenden wir jetzt die Karte, die dasselbe ist, aber sprachneutraler. Maps benötigt zwei Argumente:

(i) eine Funktion

(ii) eine iterable

Und gibt Ihnen eine Liste, in der jedes Element die Funktion ist, die auf jedes Element der Iterable angewendet wird.

Mit der Karte hätten wir also:

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

Wenn Sie Lambdas und Mapping beherrschen, haben Sie eine große Macht, Daten auf präzise Weise zu manipulieren. Lambda-Funktionen sind weder unklar noch beeinträchtigen sie die Klarheit des Codes. Verwechseln Sie etwas Hartes nicht mit etwas Neuem. Sobald Sie anfangen, sie zu verwenden, werden Sie es sehr klar finden.

Lucas Ribeiro
quelle
13

Eines der schönen Dinge lambda, die meiner Meinung nach unterschätzt werden, ist, dass es eine Möglichkeit ist, eine Bewertung für einfache Formulare aufzuschieben, bis der Wert benötigt wird. Lassen Sie mich erklären.

Viele Bibliotheksroutinen sind so implementiert, dass bestimmte Parameter aufrufbar sind (von denen Lambda einer ist). Die Idee ist, dass der tatsächliche Wert nur zu dem Zeitpunkt berechnet wird, zu dem er verwendet wird (und nicht zu dem Zeitpunkt, zu dem er aufgerufen wird). Ein (erfundenes) Beispiel könnte helfen, den Punkt zu veranschaulichen. Angenommen, Sie haben eine Routine, die einen bestimmten Zeitstempel protokolliert. Sie möchten, dass die Routine die aktuelle Zeit minus 30 Minuten verwendet. Du würdest es so nennen

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

Angenommen, die eigentliche Funktion wird nur aufgerufen, wenn ein bestimmtes Ereignis eintritt und der Zeitstempel erst zu diesem Zeitpunkt berechnet werden soll. Sie können dies so tun

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

Angenommen, die log_timestampDose kann solche Callables verarbeiten, wird dies bei Bedarf ausgewertet und Sie erhalten zu diesem Zeitpunkt den Zeitstempel.

Es gibt natürlich alternative Möglichkeiten, dies zu tun ( operatorzum Beispiel mit dem Modul), aber ich hoffe, ich habe den Punkt vermittelt.

Update : Hier ist ein etwas konkreteres Beispiel aus der Praxis.

Update 2 : Ich denke, dies ist ein Beispiel für einen sogenannten Thunk .

Noufal Ibrahim
quelle
11

Wie oben erwähnt, definiert der Lambda-Operator in Python eine anonyme Funktion, und in Python sind Funktionen Schließungen. Es ist wichtig, das Konzept der Verschlüsse nicht mit dem Operator Lambda zu verwechseln, der für sie lediglich syntaktisches Methadon ist.

Als ich vor ein paar Jahren in Python anfing, benutzte ich viel Lambdas, weil ich dachte, sie seien cool, zusammen mit Listenverständnissen. Ich habe jedoch eine große, in Python geschriebene Website mit mehreren tausend Funktionspunkten geschrieben und muss diese pflegen. Ich habe aus Erfahrung gelernt, dass Lambdas möglicherweise in Ordnung sind, um Prototypen zu erstellen, aber nichts über Inline-Funktionen (benannte Verschlüsse) bieten, außer ein paar Tastenanschläge zu speichern oder manchmal auch nicht.

Grundsätzlich läuft dies auf mehrere Punkte hinaus:

  • Es ist einfacher, Software zu lesen, die explizit mit aussagekräftigen Namen geschrieben wurde. Anonyme Schließungen können per Definition keinen aussagekräftigen Namen haben, da sie keinen Namen haben. Diese Kürze scheint aus irgendeinem Grund auch Lambda-Parameter zu infizieren, daher sehen wir häufig Beispiele wie Lambda x: x + 1
  • Es ist einfacher, benannte Verschlüsse wiederzuverwenden, da sie mehrmals mit Namen bezeichnet werden können, wenn es einen Namen gibt, mit dem auf sie verwiesen werden kann.
  • Es ist einfacher, Code zu debuggen, der benannte Closures anstelle von Lambdas verwendet, da der Name in Tracebacks und um den Fehler herum angezeigt wird.

Grund genug, sie aufzurunden und in benannte Verschlüsse umzuwandeln. Ich habe jedoch zwei weitere Groll gegen anonyme Schließungen.

Der erste Groll ist einfach, dass sie nur ein weiteres unnötiges Schlüsselwort sind, das die Sprache durcheinander bringt.

Der zweite Groll ist tiefer und auf der Paradigmenebene, dh ich mag es nicht, dass sie einen funktionalen Programmierstil fördern, weil dieser Stil weniger flexibel ist als der Nachrichtenübermittlungs-, objektorientierte oder prozedurale Stil, weil der Lambda-Kalkül nicht Turing- ist. vollständig (zum Glück können wir in Python auch innerhalb eines Lambdas aus dieser Einschränkung ausbrechen). Die Gründe, warum Lambdas diesen Stil fördern, sind:

  • Es gibt eine implizite Rückkehr, dh sie scheinen Funktionen zu sein.

  • Sie sind ein alternativer Mechanismus zum Verbergen von Zuständen zu einem anderen, expliziteren, lesbareren, wiederverwendbareren und allgemeineren Mechanismus: Methoden.

Ich bemühe mich sehr, lambda-freies Python zu schreiben und Lambdas sofort zu entfernen. Ich denke, Python wäre eine etwas bessere Sprache ohne Lambdas, aber das ist nur meine Meinung.

Mike A.
quelle
1
"... in Python sind Funktionen Verschlüsse". Das ist nicht ganz richtig, so wie ich es verstehe. Verschlüsse sind Funktionen, aber Funktionen sind nicht immer Verschlüsse. Funktion-> Lambda x, y: x + y. Schließung-> Lambda x: Lambda y: x + y
0atman
6
"weil der Lambda-Kalkül nicht Turing-vollständig ist" ist einfach falsch, untypisierter Lambda-Kalkül ist Turing-vollständig, das ist der Grund, warum er so bedeutend ist. Sie können Rekursion mit dem Y-Kombinator erhalten,Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Antti Haapala
Wenn man zu Wikipedia geht, um die Vollständigkeit von Turing zu lesen, heißt es außerdem: "Ein klassisches Beispiel ist der Lambda-Kalkül."
Antti Haapala
Ernsthaft - Nicht vollständig - Diese Antwort muss ernsthaft bearbeitet oder zurückgezogen werden.
Tony Suffolk 66
@ MarcinŁoś Up-Voted, weil es an KISS festhält. Zum Vergleich erwähnt das K & R-Buch, dass die Verwendung der Zuweisung als Teil oder eines größeren Ausdrucks zwar kompakter, aber häufig weniger lesbar ist. Der Trendwagen zur Verwendung funktionaler Programmiermuster ist banal und klischeehaft. Es reicht aus, anzugeben, wie sie verwendet werden können, aber es ist übereifrig anzugeben, dass sie von größter Bedeutung sind, um ein kompetenter Entwickler zu werden. völlig subjektiv. Dieses Argument ist analog zu C ++ - Entwicklern, die argumentieren, dass Sprachen ohne Klassen primitiv, minderwertig und unzureichend sind. "Turing-Vollständigkeit", Argumente sind pedantisch.
typedeaf
11

Lambdas sind tatsächlich sehr mächtige Konstrukte, die aus Ideen in der funktionalen Programmierung stammen, und es ist etwas, das in naher Zukunft von Python keineswegs leicht überarbeitet, neu definiert oder entfernt werden kann. Sie helfen Ihnen beim Schreiben von Code, der leistungsfähiger ist, da Sie Funktionen als Parameter übergeben können, also die Idee von Funktionen als erstklassige Bürger.

Lambdas neigen dazu, verwirrend zu werden, aber sobald ein solides Verständnis erreicht ist, können Sie sauberen, eleganten Code wie folgt schreiben:

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

Die obige Codezeile gibt eine Liste der Quadrate der Zahlen in der Liste zurück. Natürlich können Sie es auch so machen:

def square(x):
    return x*x

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

Es ist offensichtlich, dass der frühere Code kürzer ist, und dies gilt insbesondere dann, wenn Sie die Kartenfunktion (oder eine ähnliche Funktion, die eine Funktion als Parameter verwendet) nur an einer Stelle verwenden möchten. Dies macht den Code auch intuitiver und eleganter.

Wie @David Zaslavsky in seiner Antwort erwähnte, sind Listenverständnisse nicht immer der richtige Weg, insbesondere wenn Ihre Liste Werte von einem obskuren mathematischen Weg erhalten muss.

Aus praktischer Sicht war einer der größten Vorteile von Lambdas für mich in letzter Zeit die grafische Benutzeroberfläche und die ereignisgesteuerte Programmierung. Wenn Sie sich Rückrufe in Tkinter ansehen, werden sie nur als Argumente für das Ereignis verwendet, das sie ausgelöst hat. Z.B

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

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

Was wäre, wenn Sie einige Argumente vorbringen müssten? Etwas so Einfaches wie das Übergeben von 2 Argumenten zum Speichern der Koordinaten eines Mausklicks. Sie können es einfach so machen:

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

Jetzt können Sie argumentieren, dass dies mithilfe globaler Variablen möglich ist. Möchten Sie sich jedoch wirklich Gedanken über Speicherverwaltung und Datenverlust machen, insbesondere wenn die globale Variable nur an einem bestimmten Ort verwendet wird? Das wäre nur ein schlechter Programmierstil.

Kurz gesagt, Lambdas sind fantastisch und sollten niemals unterschätzt werden. Python-Lambdas sind zwar nicht dasselbe wie LISP-Lambdas (die mächtiger sind), aber Sie können wirklich eine Menge magischer Dinge damit machen.

Varagrawal
quelle
Vielen Dank. Ich habe Ihr letztes Beispiel überhaupt nicht verstanden. Wie kommt es, dass x und y in beiden mainund definiert sind do_something_cool? Was passiert mit xund yin der Funktion? Die übergebenen Werte scheinen sofort überschrieben zu werden? Woher weiß die Funktion davon event? Könnten Sie einige Kommentare / Erklärungen hinzufügen? Vielen Dank
Sanjay Manohar
@SanjayManohar Ich übergebe xund yals Argumente an do-something-coolund deren Werte werden in der Funktion festgelegt, um zu veranschaulichen, wie Sie Lambdas verwenden können, um Argumente zu übergeben, bei denen keine erwartet werden. Die widget.bindFunktion erwartet einen eventParameter, der das GUI-Ereignis in diesem bestimmten Widget identifiziert. Ich empfehle, zur besseren Übersichtlichkeit das Programmiermodell von Tkinter zu lesen.
Varagrawal
hmm ich glaube ich verstehe das Tkinter Modell. Aber immer noch nicht ganz verstehen - Sie bestehen x,ydann x=event.x. Überschreibt das nicht den Wert, den Sie übergeben haben? Und woher weiß die Funktion, was eventist? Ich sehe nicht, wo Sie das an die Funktion übergeben. Oder ist es eine Methode? Dürfen Sie auch Minuszeichen in einem Funktionsnamen?
Sanjay Manohar
@ SanjayManohar Kumpel, du musst dich über Tkinter und Python informieren. Tkinter übergibt dem Ereignisobjekt die Funktion als Standardaktion. Dies x, yist nur ein Beispiel zur Veranschaulichung. Ich versuche die Kraft von Lambdas zu zeigen, nicht von Tkinter. :)
Varagrawal
1
OK, jetzt sehe ich, was Sie beabsichtigt haben - Sie möchten, dass die Funktion empfangen wird event? Sollte Ihr Lambda in diesem Fall nicht lesen lambda event: do_something_cool(event,x,y)?
Sanjay Manohar
8

Lambdas sind im Allgemeinen eng mit dem funktionalen Programmierstil verbunden. Die Idee, dass Sie Probleme lösen können, indem Sie eine Funktion auf einige Daten anwenden und die Ergebnisse zusammenführen, verwendet Google, um die meisten seiner Algorithmen zu implementieren.

Programme, die im funktionalen Programmierstil geschrieben wurden, lassen sich leicht parallelisieren und werden daher mit modernen Mehrkernmaschinen immer wichtiger. Kurz gesagt, NEIN, du solltest sie nicht vergessen.

Yogi
quelle
7

Erste Glückwünsche, die es geschafft haben, Lambda herauszufinden. Meiner Meinung nach ist dies ein wirklich mächtiges Konstrukt, mit dem man handeln kann. Der heutige Trend zu funktionalen Programmiersprachen ist sicherlich ein Indikator dafür, dass er weder vermieden werden sollte noch in naher Zukunft neu definiert wird.

Man muss nur ein bisschen anders denken. Ich bin sicher, bald wirst du es lieben. Aber seien Sie vorsichtig, wenn Sie sich nur mit Python beschäftigen. Da das Lambda kein wirklicher Verschluss ist, ist es irgendwie "kaputt": Pythons Lambda ist kaputt

Norbert Hartl
quelle
Pythons Lambda ist nicht kaputt. Es gibt zwei Möglichkeiten, mit Einheimischen in Lambdas umzugehen. Beide haben Vor- und Nachteile. Ich denke, der Ansatz von Python (und C #) ist wahrscheinlich nicht intuitiv für diejenigen, die eher an rein funktionale Sprachen gewöhnt sind, da ich bei einer rein funktionalen Sprache nicht denke, dass dieser Ansatz überhaupt Sinn macht.
Brian
Es ist in der Tat nicht intuitiv. Ich bin kein Python-Programmierer, aber in quietschendem Smalltalk ist es dasselbe und ich stolpere regelmäßig darüber. Also selbst ich würde es als "kaputt" betrachten :)
Norbert Hartl
Nein, das hat nichts mit Gegenintuitivität zu tun. Es ist nur so, dass der lexikalische Bereich von Variablennamen der einer Funktion ist; Eine Schleife führt keinen lexikalischen Bereich ein. Funktionen funktionieren auch in Javascript auf die gleiche Weise. Wenn Sie einen Bereich für var benötigen, können Sie dies jederzeit tun (Lambda Scopedvar: Lambda x: Scopedvar + x) ()
Antti Haapala
6

Ich fange gerade mit Python an und renne mit dem Kopf voran nach Lambda - was eine Weile gedauert hat, bis ich es herausgefunden habe.

Beachten Sie, dass dies keine Verurteilung von irgendetwas ist. Jeder hat eine andere Reihe von Dingen, die nicht einfach kommen.

Ist Lambda eines dieser „interessanten“ Sprachelemente, die im wirklichen Leben vergessen werden sollten?

Nein.

Ich bin mir sicher, dass es einige Randfälle gibt, in denen dies erforderlich sein könnte, aber angesichts der Dunkelheit.

Es ist nicht dunkel. In den letzten 2 Teams, an denen ich gearbeitet habe, haben alle diese Funktion die ganze Zeit genutzt.

das Potenzial einer Neudefinition in zukünftigen Versionen (meine Annahme basiert auf den verschiedenen Definitionen davon)

Ich habe keine ernsthaften Vorschläge zur Neudefinition in Python gesehen, außer die Korrektur der Abschlusssemantik vor einigen Jahren.

und die reduzierte Codierungsklarheit - sollte dies vermieden werden?

Es ist nicht weniger klar, ob Sie es richtig verwenden. Im Gegenteil, mehr Sprachkonstrukte zur Verfügung zu haben, erhöht die Klarheit.

Dies erinnert mich an ein Überlaufen (Pufferüberlauf) von C-Typen - Zeigen auf die oberste Variable und Überladen, um die anderen Feldwerte festzulegen ... eine Art Technikfreak, aber ein Alptraum für Wartungscodierer.

Lambda ist wie Pufferüberlauf? Beeindruckend. Ich kann mir nicht vorstellen, wie Sie Lambda verwenden, wenn Sie denken, dass es ein "Wartungsalptraum" ist.

Ken
quelle
5
-1 dafür, dass ich (und andere) die ganze Frage noch einmal gelesen haben. Beachten Sie, dass andere es geschafft haben, zu antworten, ohne es zu tun.
Paweł Polewicz
6

Ich benutze Lambdas, um Codeduplikationen zu vermeiden. Dies würde die Funktion leicht verständlich machen. ZB:

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

Ich ersetze das durch ein temporäres Lambda

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
quelle
5

Ich habe heute angefangen, David Mertz 'Buch "Textverarbeitung in Python" zu lesen. Obwohl er eine ziemlich knappe Beschreibung von Lambda hat, ließen die Beispiele im ersten Kapitel in Kombination mit der Erklärung in Anhang A sie (endlich) für mich von der Seite springen und plötzlich verstand ich ihren Wert. Das heißt nicht, dass seine Erklärung für Sie funktionieren wird und ich mich noch in der Entdeckungsphase befinde. Daher werde ich nicht versuchen, diese Antworten zu ergänzen, außer den folgenden: Ich bin neu in Python Ich bin neu in OOP Lambdas waren ein Kampf für mich Jetzt, wo ich Mertz lese, denke ich, dass ich sie bekomme und ich sehe sie als sehr nützlich an, da ich denke, dass sie einen saubereren Ansatz für die Programmierung ermöglichen.

Er reproduziert das Zen von Python, von dem eine Zeile Einfach ist besser als komplex. Als Nicht-OOP-Programmierer, der Code mit Lambdas liest (und bis letzte Woche Listenverständnisse hat), habe ich gedacht: Das ist einfach? . Heute wurde mir endlich klar, dass diese Funktionen den Code tatsächlich viel lesbarer und verständlicher machen als die Alternative - die ausnahmslos eine Art Schleife ist. Ich habe auch festgestellt, dass Python wie ein Jahresabschluss nicht für Anfänger gedacht ist, sondern für Benutzer, die sich weiterbilden möchten. Ich kann nicht glauben, wie mächtig diese Sprache ist. Als mir (endlich) der Zweck und der Wert von Lambdas klar wurde, wollte ich ungefähr 30 Programme zerreißen und gegebenenfalls wieder Lambdas einbauen.

PyNEwbie
quelle
5

Ein nützlicher Fall für die Verwendung von Lambdas ist die Verbesserung der Lesbarkeit des Verständnisses langer Listen . In diesem Beispiel loop_dicist die Klarheit kurz, aber stellen Sie sich vor, Sie loop_dicwären sehr lang. Wenn Sie nur einen einfachen Wert verwenden würden, der ianstelle der Lambda-Version dieses Werts enthält, erhalten Sie einen 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'}]

Anstatt

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

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

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

Ich kann Ihnen ein Beispiel geben, wo ich Lambda wirklich ernst brauchte. Ich mache ein grafisches Programm, bei dem die Verwendung mit der rechten Maustaste auf eine Datei klickt und ihr eine von drei Optionen zuweist. Es stellt sich heraus, dass in Tkinter (dem GUI-Schnittstellenprogramm, in das ich dies schreibe), wenn jemand eine Taste drückt, es keinem Befehl zugewiesen werden kann, der Argumente aufnimmt. Wenn ich also eine der Optionen gewählt habe und das Ergebnis meiner Wahl sein möchte:

print 'hi there'

Dann keine große Sache. Aber was ist, wenn ich meine Wahl brauche, um ein bestimmtes Detail zu haben? Wenn ich beispielsweise Auswahl A wähle, wird eine Funktion aufgerufen, die ein Argument aufnimmt, das von der Auswahl A, B oder C abhängt. TKinter konnte dies nicht unterstützen. Lamda war die einzige Möglichkeit, dies zu umgehen ...

Glueberg
quelle
2
Nun, vermutlich hättest du es tun können def foo...und dann foostatt übergeben lambda. Es ist nur mehr Code und Sie müssen sich einen Namen einfallen lassen.
Jon Coombs
4

Ich benutze es ziemlich oft, hauptsächlich als Nullobjekt oder um Parameter teilweise an eine Funktion zu binden.

Hier einige Beispiele:

So implementieren Sie ein Nullobjektmuster:

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

zur Parameterbindung:

Angenommen, ich habe die folgende API

def dump_hex(file, var)
    # some code
    pass

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

Wenn ich dann die empfangenen Daten nicht schnell in eine Datei kopieren möchte, mache ich das:

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

ich benutze lambda , um Rückrufe zu erstellen, die Parameter enthalten. Es ist sauberer, ein Lambda in eine Zeile zu schreiben, als eine Methode zu schreiben, um dieselbe Funktionalität auszuführen.

Zum Beispiel:

import imported.module

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

im Gegensatz zu:

import imported.module

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

Ich bin ein Python-Anfänger. Um eine klare Vorstellung von Lambda zu bekommen, habe ich es mit einer 'for'-Schleife verglichen. in Bezug auf die Effizienz. Hier ist der 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
quelle
6
Möglicherweise interessiert Sie das timeitModul, das in der Regel genauere Ergebnisse liefert als das Subtrahieren von time.time()Werten.
Kevin
2
Hmm, müssen Sie Ihren Timer nicht zu Beginn von first () und second () neu starten?
Qneill
2

Lambda ist ein Prozedurkonstruktor. Sie können Programme zur Laufzeit synthetisieren, obwohl Pythons Lambda nicht sehr leistungsfähig ist. Beachten Sie, dass nur wenige Menschen diese Art der Programmierung verstehen.

Nick Dandoulakis
quelle