Wie erstelle ich eine Liste von Python Lambda-Ausdrücke (in einer Liste verstehen/for-Schleife)?
Ich möchte eine Liste erstellen von lambda-Objekte aus einer Liste von Konstanten in Python; zum Beispiel:
listOfNumbers = [1,2,3,4,5]
square = lambda x: x * x
listOfLambdas = [lambda: square(i) for i in listOfNumbers]
Dadurch wird eine Liste der lambda-Objekte, jedoch, wenn ich Sie laufen:
for f in listOfLambdas:
print f(),
Ich würde erwarten, dass es drucken würde
1 4 9 16 25
Statt, druckt er:
25 25 25 25 25
Es scheint, als ob die lambdas haben alle die falschen parameter. Habe ich etwas falsch gemacht, und gibt es eine Möglichkeit es zu beheben? Ich bin in Python 2.4, denke ich.
EDIT: ein bisschen mehr versucht, Dinge, und so kam mit dieser:
listOfLambdas = []
for num in listOfNumbers:
action = lambda: square(num)
listOfLambdas.append(action)
print action()
Druckt die erwartete Quadrate von 1 bis 25, dann aber mit der früheren print-Anweisung:
for f in listOfLambdas:
print f(),
gibt mir immer noch alle 25
s. Wie hat sich die vorhandene lambda-Objekte sich ändern, zwischen den beiden print-Anrufe?
Verwandte Frage: Warum Ergebnisse von map() und list-comprehension unterschiedlich sind?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich vermute, dass die lambda-Sie erstellen in der Liste der Verständigung gebunden an die variable i, die schließlich landet auf 5. Also, wenn Sie bewerten den lambdas nach die Tatsache, dass Sie alle gebunden sind, 5 und am Ende der Berechnung 25. Das gleiche geschieht mit der num in deinem zweiten Beispiel. Wenn Sie bewerten den lambda-Ausdruck innerhalb der Schleife ist es num hat sich nicht geändert, so dass Sie die richtige Wert. Nach der Schleife, num 5...
Ich bin mir nicht ganz sicher, was Sie für gehen, so bin ich nicht sicher, wie Sie Sie vorschlagen, eine Lösung. Wie wäre es damit?
Das gibt mir die erwartete Ausgabe:
Einen anderen Weg, dies zu betrachten ist, dass ein lambda "erfasst", seine lexikalische Umgebung an der Stelle, wo es erstellt wird. Also, wenn Sie geben es num es nicht wirklich beheben, dass Wert, bis Ihr aufgerufen. Dies ist sowohl verwirrend und mächtig.
Haben Sie:
Ausgabe:
Müssen Sie currying! Abgesehen davon, dass lecker, verwenden Sie diesen Standard-Wert "hack".
Ausgabe:
Hinweis: die
i=i
. Das ist, wo die Magie passiert.Wenn-Funktion-Anweisungen ausgeführt werden, sind Sie verpflichtet, Ihre (lexikalisch) umschließenden scope.
In Ihrem snippet, der Lambda-Ausdrücke gebunden sind, um den globalen scope, weil
for
Suiten sind nicht ausgeführt, wie eine unabhängig Gültigkeitsbereich Einheit in Python. Am Ende derfor
Schleife, dienum
gebunden ist, in den umschließenden scope. Demo:Also beim binden von Bezeichnern, die
for
Schleife bist du eigentlich mit der Manipulation der umschließenden scope.Gleiche Angebot für die Liste Verstehens:
Geist weht, ich weiß. Anywho, mit unserem neu gewonnenen wissen, können wir feststellen, dass die Lambda-Ausdrücke, die Sie erstellen, werden auf der (einzigen)
num
Bezeichner gebunden in den umschließenden scope. Sollte dies mehr Sinn machen:Und hier ist das coolste Teil, die es zeigt noch mehr:
So die Lösung von dieser, natürlich, ist es, eine neue umschließenden Bereich für jeden
number
Sie binden möchten. In Python können Sie neue umschließenden Bereiche mit Modulen, Klassen und Funktionen. Es ist üblich, eine Funktion verwenden, nur zum erstellen neuer umschließenden scope, der für eine andere Funktion.In Python, ein Schließung ist eine Funktion, die gibt eine weitere Funktion. Wie eine Art Konstruktor-Funktion. Check-out
get_fun
im folgenden Beispiel:Seit
get_fun
ist eine Funktion, die es bekommt seinen eigenen internen Bereich. Jedes mal, wenn Sie rufenget_fun
mit einem Wert, der eine kleine Tabelle erstellt, um zu verfolgen Bindungen in ihm; d.h. er sagt, "In diesem Rahmen, dievalue
identifier Punkte auf die Sache, die übergeben wurde." Dieser Bereich geht Weg am Ende der Ausführung der Funktion, es sei denn, es gibt einen Grund für Sie, um zu hängen.Wenn Sie der Rückgabe einer Funktion innerhalb eines Bereichs, das ist ein guter Grund für Teile der "Rahmen-Tabelle" herum zu hängen,--, die Funktion, die Sie zurückgeben könnte, Referenz Sachen aus diesem Bereich der Tabelle, wenn Sie rufen Sie es später. Aus diesem Grund, wenn
fun
inget_fun
Python erzähltfun
überget_fun
's scope-Tabelle, diefun
hält, praktisch, wenn' s nötig ist.Lesen Sie mehr über die details und technische Terminologie (die ich erweicht ein bisschen) in die Python-docs auf dem Ausführungsmodell. Sie können auch einen Blick auf die Teile der umschließenden scope, der eine Funktion bezeichnet, mit
print fun.__closure__
. In dem obigen sehen wir, dass der Verweis auf dievalue
,, die passiert werden die ein int:Oder
Finde ich manchmal, dass die Festlegung der tatsächlichen Klassen, die für die Funktion Objekte macht es einfacher zu verstehen, was Los ist:
Zugegeben, es ist ein wenig Ausführlicher als die Verwendung von Lambda-Ausdrücke oder closures, aber ich finde diese leichter zu verstehen, wenn ich versuche zu tun, nicht offensichtliche Dinge, die mit Funktionen.
Versuchen zu verwenden () statt []:
Und Sie erhalten:
Könnten Sie auch tun:
Als zusätzlichen Kommentar möchte ich kurz die Möglichkeit zum generieren von Listen von lambda-Funktionen von sympy Matrizen (ich weiß nicht, ob es ist der beste Weg, es zu tun, aber das ist, wie ich es Tue und finde ich es praktisch):