2016-12-06 7 views
3

Ich schrieb diesen einfachen Code:Python umgebenden Gültigkeitsbereich Variablen mit Lambda-Funktion

def makelist(): 
    L = [] 
    for i in range(5): 
    L.append(lambda x: i**x) 
    return L 

ok, jetzt nenne ich

mylist = makelist() 

weil der umschließenden Umfang Variable wird nachgeschlagen, wenn die verschachtelte Funktionen später sind aufgerufen Sie erinnern sich alle an den gleichen Wert: deshalb erwartete ich, den Wert zu finden, den die Schleifenvariable bei der letzten Schleifeniteration hatte, aber wenn ich meine Liste überprüfe, sehe ich:

>>> mylist[0](0) 
1 
>>> mylist[0](1) 
4 
>>> mylist[0](2) 
16 
>>> 

Ich bin so verwirrt, warum mein Code die letzten for-Schleife Werte nicht behält? Warum muss ich behalten nicht explizit Umfang Werte mit Standardargumenten wie diese umschließenden:

L.append(lambda x, i=i: i ** x) 

Vielen Dank im Voraus

Antwort

3

Auch wenn i mehrere Werte im Laufe der Zeit nimmt, gibt es effektiv nur eine Variable, i. Der Inhalt von i wird während der Schleife geändert. Aber die Schließungen erfassen Variablen, keine Werte. Nichts wird innerhalb des Lambda ausgewertet, bis Sie es aufrufen. Zu dem Zeitpunkt, an dem Sie die Funktion aufrufen, greifen Sie auf den aktuellen Wert i zu, der zufällig der letzte ist.

Was, warum i=i löst das Problem, wird dies in The Hitchhiker's guide to Python (Gemeinsamen Gotchas) zum Beispiel erklärt:

Pythons Standardargumente werden einmal ausgewertet, wenn die Funktion definiert ist, wird die Funktion nicht jedes Mal ist genannt (wie es in sagen, Ruby). Das heißt, wenn Sie ein veränderbares Standardargument verwenden und es mutieren, werden Sie dieses Objekt für alle zukünftigen Aufrufe an die Funktion ebenfalls mutiert haben.

Und so, jede frische Bindung, die innerhalb des Verschlusses auftritt, den Sie erstellen (und zufällig i benannt werden wie derjenige außen) hat den Standardwert berechnet wird, wenn die Schließung zu schaffen. Folglich haben Sie den "richtigen" Wert an Ort und Stelle, bereit, verwendet zu werden, wenn die Schließung aufgerufen wird.

3

Zuerst zu beachten, dass alle fünf Funktionen in der Liste identisch sind, weil sie alle verwenden final Wert von i von innen makelist.

i, obwohl, ist Teil der Schließung erstellt, wenn die lambda Ausdrücke ausgewertet wurden. Das heißt, wenn Sie i in dem Bereich, in dem Sie eine Funktion von makelist aufrufen, einen neuen Wert zuweisen, hat dies keine Auswirkungen auf die Funktionen. Sie suchen den Wert von i aus dem Namespace, der der Funktion als Ergebnis der Schließung zugeordnet ist, nicht aus dem globalen Bereich.

Verwandte Themen