Lambdas innerhalb der Listenergänzungen

7

Ich wollte eine Liste von Lambdas haben, die als eine Art Cache für einige schwere Berechnungen dienen und dies bemerkt haben:

%Vor%

Obwohl

%Vor%

Das bedeutet, dass die Lambdas eindeutige Funktionen sind, aber sie haben alle den gleichen Indexwert.

Ist das ein Fehler oder eine Funktion? Wie vermeide ich dieses Problem? Es ist nicht beschränkt auf Listenergänzungen ...

%Vor%     
ubershmekel 09.04.2012, 07:57
quelle

5 Antworten

13

Der lambda gibt den Wert von i zum Zeitpunkt des Aufrufs zurück. Da Sie lambda aufrufen, nachdem die Schleife beendet wurde, ist der Wert von i immer 9.

Sie können eine lokale i -Variable im Lambda erstellen, um den Wert zu dem Zeitpunkt beizubehalten, zu dem lambda definiert wurde:

%Vor%

Eine andere Lösung besteht darin, eine Funktion zu erstellen, die lambda zurückgibt:

%Vor%

Dies funktioniert, weil für jeden Aufruf von i ein anderer Abschluss (mit einem anderen Wert von create_lambda ) erstellt wurde.

    
interjay 09.04.2012, 08:08
quelle
7

Was Sie hier sehen, ist der Effekt von Sperrungen . Das Lambda erfasst den Status aus dem Programm, das später verwendet werden soll. Während also jedes Lambda ein einzigartiges Objekt ist, ist der Zustand nicht unbedingt einzigartig.

Das eigentliche 'Gotchya' hier ist, dass die Variable i erfasst wird, nicht der Wert, den i zu diesem Zeitpunkt darstellt. Wir können dies mit einem viel einfacheren Beispiel illustrieren:

%Vor%

Das Lambda behält den Verweis auf die Variable und wertet diese Variable aus, wenn Sie das Lambda ausführen.

Um dies zu umgehen, können Sie einer lokalen Variable innerhalb des Lambda zuweisen:

%Vor%

Schließlich wird im Falle einer Schleife die Schleifenvariable nur einmal deklariert. Daher bleiben alle Verweise auf die Schleifenvariable innerhalb der Schleife über die nächste Iteration hinaus bestehen. Dies beinhaltet die Variable in Listenübersetzungen.

    
Josh Smeaton 09.04.2012 08:07
quelle
1

Das Problem ist, dass Sie den Wert von i nicht bei jeder Iteration des Listenverständnisses erfassen, sondern die Variable jedes Mal erfassen.

Das Problem besteht darin, dass eine Schließung Variablen per Referenz erfasst. In diesem Fall erfassen Sie eine Variable, deren Wert sich im Laufe der Zeit ändert (wie bei allen Schleifenvariablen), so dass sie bei der Ausführung einen anderen Wert hat als bei ihrer Erstellung.

    
avasal 09.04.2012 08:08
quelle
0

Ich bin mir nicht sicher, ob es ein Fehler oder eine Funktion ist, aber was passiert, ist, dass lambda:i i nicht auswertet, bevor die Lambda-Funktion gebildet wird. Also ist es buchstäblich nur eine Funktion, die den aktuellen Wert von i auswertet. Hier ist ein weiteres Beispiel, wie dies geschieht.

%Vor%

Also, offensichtlich ist das Gleiche, außer dass ich in Ihren Beispielen 9 anwende, da es in dieser Reihenfolge durch den Bereich von 0 bis 9 zugewiesen wird.

Ich glaube nicht, dass es wirklich einen guten Weg gibt, es zu vermeiden. Lambda-Funktionen in Python sind ziemlich begrenzt. Es ist nicht wirklich eine funktionale Sprache im Herzen.

    
Keith Irwin 09.04.2012 08:06
quelle
0

Ich bin mir nicht sicher, was Sie mit Ihrer Lambda-Funktion machen wollen. Es braucht kein Argument ...

Ich denke, dass Python einen Generator ähnlich wie (i for i in range(10)) erstellt und dann iteriert. Nachdem es 10 Mal zählt, ist der endgültige Wert von i 9, und das ist dann, was die Lambda-Funktion zurückgibt.

Wollten Sie irgendeine Art von Objekt machen, das die Zahlen von [0,9] ergeben würde? Wenn Sie dies tun wollen, verwenden Sie einfach xrange(10) , was einen Iterator liefert, der die Zahlen [0.9] ergibt.

%Vor%

Hinweis: Ich denke, es ist eine sehr schlechte Idee, eine Funktion j() zu benennen. Python verwendet j , um den Imaginärteil einer komplexen Zahl anzugeben, und ich denke, eine Funktion namens j könnte den Parser verwirren. Ich habe einige merkwürdige Fehlermeldungen erhalten, die versuchen, Ihren Code auszuführen.

    
steveha 09.04.2012 08:21
quelle