Frage

Der folgende Test fehlschlägt:

#!/usr/bin/env python
def f(*args):
    """
    >>> t = 1, -1
    >>> f(*map(lambda i: lambda: i, t))
    [1, -1]
    >>> f(*(lambda: i for i in t)) # -> [-1, -1]
    [1, -1]
    >>> f(*[lambda: i for i in t]) # -> [-1, -1]
    [1, -1]
    """
    alist = [a() for a in args]
    print(alist)

if __name__ == '__main__':
    import doctest; doctest.testmod()

Mit anderen Worten:

>>> t = 1, -1
>>> args = []
>>> for i in t:
...   args.append(lambda: i)
...
>>> map(lambda a: a(), args)
[-1, -1]
>>> args = []
>>> for i in t:
...   args.append((lambda i: lambda: i)(i))
...
>>> map(lambda a: a(), args)
[1, -1]
>>> args = []
>>> for i in t:
...   args.append(lambda i=i: i)
...
>>> map(lambda a: a(), args)
[1, -1]
War es hilfreich?

Lösung

Sie sind anders, weil der Wert von i sowohl in dem Generator Ausdruck und die Liste comp lazily ausgewertet werden, das heißt, wenn die anonymen Funktionen in f aufgerufen werden.
Zu diesem Zeitpunkt wird i auf den letzten Wert, wenn t gebunden, die -1 ist.

Also im Grunde ist es das, was die Liste Verständnis tut (ebenfalls für die genexp):

x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)

Nun ist der Lambda-Ausdrücke trägt um einen Verschluss, den i verweist, aber i auf -1 in beiden Fällen gebunden, denn das ist der letzte Wert ist es zugewiesen wurde.

Wenn Sie wollen sicherstellen, dass das Lambda den aktuellen Wert von i empfängt, tut

f(*[lambda u=i: u for i in t])

Auf diese Weise zwingen Sie die Auswertung von i zum Zeitpunkt der Schließung erstellt wird.

Bearbeiten : Es gibt einen Unterschied zwischen Generator Ausdrücke und Listenkomprehensionen. Letztere Leck der Schleifenvariablen in den umgebenden Rahmen

Andere Tipps

Das Lambda erfaßt Variablen, nicht Werte, daher der Code

lambda : i

immer den Wert zurück i ist zur Zeit gebunden in der Schließung. Zu der Zeit, es aufgerufen wird, hat sich dieser Wert auf -1 gesetzt wurde.

bekommen, was Sie wollen, müssen Sie die tatsächliche Bindung zu dem Zeitpunkt erfassen wird das Lambda, erstellt von:

>>> f(*(lambda i=i: i for i in t)) # -> [-1, -1]
[1, -1]
>>> f(*[lambda i=i: i for i in t]) # -> [-1, -1]
[1, -1]

Expression f = lambda: i entspricht:

def f():
    return i

Expression g = lambda i=i: i entspricht:

def g(i=i):
    return i

i ist ein freien Variable im ersten Fall rel="nofollow und es ist an den gebundenen Funktionsparameter in dem zweiten Fall, dh es ist eine lokale Variable in diesem Fall. Die Werte für die Standardparameter werden zum Zeitpunkt der Funktionsdefinition ausgewertet.

Generator Ausdruck ist der nächste umgebende Gültigkeitsbereich (wo i definiert ist) für i Namen in dem lambda Ausdruck, daher i in diesem Block aufgelöst wird:

f(*(lambda: i for i in (1, -1)) # -> [-1, -1]

i ist eine lokale Variable des lambda i: ... Block daher die Aufgabe bezieht er sich auf in diesem Block definiert sind:

f(*map(lambda i: lambda: i, (1,-1))) # -> [1, -1]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top