Python Lambda Verschluss Scoping

Ich versuche, Verschlüsse zu verwenden, um eine Variable aus einer Funktionssignatur zu entfernen (die Anwendung soll das Schreiben aller Funktionen, die zum Verbinden von Qt-Signalen für eine Schnittstelle erforderlich sind, um eine größere Anzahl von Parametern an das Wörterbuch zu steuern, das die Werte speichert)

Ich verstehe nicht, warum der Fall der Verwendung des lambda nicht in eine andere Funktion eingehüllt den Nachnamen für alle Fälle zurückgibt.

 names = ['a','b','c'] def test_fun(name,x): print name,x def gen_clousure(name): return lambda x: test_fun(name,x) funcs1 = [gen_clousure(n) for n in names] funcs2 = [lambda x: test_fun(n,x) for n in names] # this is what I want In [88]: for f in funcs1: ....: f(1) a 1 b 1 c 1 # I do not understand why I get this In [89]: for f in funcs2: ....: f(1) c 1 c 1 c 1 

    One Solution collect form web for “Python Lambda Verschluss Scoping”

    Der Grund dafür ist, dass Verschlüsse (Lambdas oder sonst) sich über Namen schließen, nicht Werte. Wenn du lambda x: test_fun(n, x) , wird das n nicht ausgewertet, da es sich in der Funktion befindet. Es wird ausgewertet, wenn die Funktion aufgerufen wird , zu welcher Zeit der Wert, der da ist, der letzte Wert aus der Schleife ist.

    Sie sagen am Anfang, dass Sie "Verschlüsse verwenden möchten, um eine Variable aus einer Funktionssignatur zu eliminieren", aber es funktioniert nicht wirklich so. (Siehe unten, aber für eine Art und Weise, die Sie befriedigen kann, je nachdem, was Sie unter "Beseitigen" bedeuten.) Variablen innerhalb des Funktionskörpers werden nicht ausgewertet, wenn die Funktion definiert ist. Um die Funktion zu erhalten, einen "Snapshot" der Variablen zu nehmen, wie sie zur Funktionsdefinitionszeit existiert, müssen Sie die Variable als Argument übergeben. Der übliche Weg, dies zu tun, ist, der Funktion ein Argument zu geben, dessen Standardwert die Variable aus dem äußeren Bereich ist. Schauen Sie sich den Unterschied zwischen diesen beiden Beispielen an:

     >>> stuff = [lambda x: n+x for n in [1, 2, 3]] >>> for f in stuff: ... print f(1) 4 4 4 >>> stuff = [lambda x, n=n: n+x for n in [1, 2, 3]] >>> for f in stuff: ... print f(1) 2 3 4 

    Im zweiten Beispiel wird n als Argument an die Funktion "sperrt" den aktuellen Wert von n zu dieser Funktion übergeben. Du musst so etwas machen, wenn du den Wert auf diese Weise einsperren möchtest. (Wenn es nicht so funktioniert, würden Dinge wie globale Variablen überhaupt nicht funktionieren, es ist wichtig, dass freie Variablen zum Zeitpunkt der Nutzung aufgeschlagen werden.)

    Beachten Sie, dass nichts über dieses Verhalten ist spezifisch für Lambdas. Die gleichen Scoping-Regeln sind in der Tat, wenn Sie def , um eine Funktion zu definieren, die Variablen aus dem umschließenden Bereich verweist.

    Wenn Sie wirklich wollen, können Sie vermeiden, das zusätzliche Argument zu Ihrer zurückgegebenen Funktion hinzuzufügen, aber um dies zu tun, müssen Sie diese Funktion in einer anderen Funktion umwickeln, wie folgt:

     >>> def makeFunc(n): ... return lambda x: x+n >>> stuff = [makeFunc(n) for n in [1, 2, 3]] >>> for f in stuff: ... print f(1) 2 3 4 

    Hier sieht das innere Lambda immer noch den Wert von n wenn es genannt wird. Aber das n , auf das es sich bezieht, ist nicht mehr eine globale Variable, sondern eine lokale Variable innerhalb der umschließenden Funktion makeFunc . Ein neuer Wert dieser lokalen Variablen wird jedes Mal erstellt, wenn makeFunc aufgerufen wird, und das zurückgegebene Lambda erzeugt eine Schließung, die den lokalen Variablenwert speichert, der für den Aufruf von makeFunc . Somit hat jede in der Schleife erzeugte Funktion eine eigene "private" Variable namens x . (Für diesen einfachen Fall kann dies auch mit einem Lambda für die äußere Funktion erfolgen — stuff = [(lambda n: lambda x: x+n)(n) for n in [1, 2, 3]] – – aber das ist weniger lesbar.)

    Beachten Sie, dass Sie immer noch Ihre n als Argument passieren müssen, es ist nur so, indem Sie es auf diese Weise tun, geben Sie es nicht als Argument an die gleiche Funktion, die winds up geht in die stuff Liste; Stattdessen gehst du es als Argument an eine Helfer-Funktion, die die Funktion schafft, die du in stuff setzen willst. Der Vorteil der Verwendung dieser Zwei-Funktions-Ansatz ist, dass die zurückgegebene Funktion ist "sauber" und hat nicht das zusätzliche Argument; Dies könnte nützlich sein, wenn Sie verpacken Funktionen, die eine Menge von Argumenten akzeptiert, in welchem ​​Fall könnte es verwirrend zu erinnern, wo die n Argument war in der Liste. Der Nachteil ist, dass auf diese Weise, der Prozess der Herstellung der Funktionen ist komplizierter, da Sie eine andere Umschließung Funktion benötigen.

    Das Ergebnis ist, dass es einen Kompromiss gibt: Sie können den Funktionserzeugungsprozess einfacher machen (dh keine Notwendigkeit für zwei verschachtelte Funktionen), aber dann müssen Sie die daraus resultierende Funktion etwas komplizierter machen (dh es hat diese extra n=n Argument). Oder Sie können die Funktion einfacher machen (dh es hat kein n= n Argument), aber dann müssen Sie den Funktionserzeugungsprozess komplizierter machen (dh Sie benötigen zwei verschachtelte Funktionen, um den Mechanismus zu implementieren).

    Python ist die beste Programmiersprache der Welt.