На Python представлен код: 'lst = [lambda i: i*n for n in range(3)]; print([f(2) for f in lst])' Объясните результат и предложите исправление, если поведение не соответствует ожиданиям
Коротко: проблема — «позднее связывание» (closure захватывает переменную, а не её текущее значение). В вашем коде создаются три лямбды в цикле range(3)\text{range}(3)range(3), но все они используют одну и ту же переменную nnn, которая после цикла равна 222. Поэтому при вызове f(2)f(2)f(2) для каждой функции получается 2⋅2=42\cdot 2=42⋅2=4 и выводится [4,4,4][4,4,4][4,4,4]. Почему так: лямбда обращается к имени nnn при выполнении, а не при создании. Исправления (два простых варианта): 1) Захват значения через параметр по умолчанию: lst = [lambda i, n=n: i*n for n in range(3)] print([f(2) for f in lst]) # выводит [0,2,4][0,2,4][0,2,4] 2) Использовать фабрику функций: def make(n): return lambda i: i*n lst = [make(n) for n in range(3)] print([f(2) for f in lst]) # выводит [0,2,4][0,2,4][0,2,4] Оба варианта фиксируют текущее значение nnn при создании каждой функции.
Почему так: лямбда обращается к имени nnn при выполнении, а не при создании.
Исправления (два простых варианта):
1) Захват значения через параметр по умолчанию:
lst = [lambda i, n=n: i*n for n in range(3)]
print([f(2) for f in lst]) # выводит [0,2,4][0,2,4][0,2,4]
2) Использовать фабрику функций:
def make(n):
return lambda i: i*n
lst = [make(n) for n in range(3)]
print([f(2) for f in lst]) # выводит [0,2,4][0,2,4][0,2,4]
Оба варианта фиксируют текущее значение nnn при создании каждой функции.