Код говорит больше:
from pprint import pprint li = [] for i in range(5): li.append(lambda : pprint(i)) for k in li: k()
выход:
4 4 4 4 4
почему бы и нет
0 1 2 3 4
??
Спасибо.
P.S. Если я напишу полный декоратор, он будет работать как положено:
from pprint import pprint li = [] #for i in range(5): #li.append(lambda : pprint(i)) def closure(i): def _func(): pprint(i) return _func for i in range(5): li.append(closure(i)) for k in li: k()
вам нужно сделать:
lambda i=i: pprint(i)
вместо того, чтобы зафиксировать текущее значение i
i
Если вы не хотите использовать аргумент по умолчанию - который может привести к ошибкам при случайном вызове с аргументом - вы можете использовать вложенную лямбду:
from pprint import pprint li = [] for i in range(5): li.append((lambda x: lambda: pprint(x))(i)) for k in li: k()
Это анонимная версияваша closure функция.
closure
Правильно ссылается на i, единственное, что к тому времени, когда ваш список будет заполнен, i будет иметь значение, назначенное из последнего элемента в последовательности, когда итерация закончилась, поэтому вы видите 4 все кончено.
4
Ответ: поскольку код внутри лямбды использует вашу глобальную переменную i.
Ваш второй вариант будет аналогичен первому варианту с лямбда, если удалить параметр i:
def closure():
Вместо
def closure(i):
Т.е. код внутри функции будет использовать глобальную переменную i.
Лямбда-функции создают замыкания над переменной i. После завершения первого цикла for значение i 4.
for
Затем запускается второй цикл for и выполняются все лямбда-функции. Затем каждый из них печатает текущее значение i, которое равно 4.