Разберите Python-фрагмент с замыканиями: funcs = []; for i in range(5): funcs.append(lambda: i); print([f() for f in funcs]) — почему все функции возвращают одно и то же значение, как это исправить и какие альтернативные конструкции избежать подобных ловушек?

19 Мар в 12:09
36 +1
0
Ответы
1
Коротко — потому что замыкание захватывает переменную `i`, а не её значение; к моменту вызова всех лямбд `i` равно последнему значению цикла. В вашем примере цикл по `range(5)` даёт значения 0,1,2,3,40,1,2,3,40,1,2,3,4, но после окончания `i` равно 444, поэтому
- оригинальный код
funcs = []
for i in range(5):
funcs.append(lambda: i)
print([f() for f in funcs])
выведет [ 4,4,4,4,4 ][\;4,4,4,4,4\;][4,4,4,4,4].
Как исправить (варианты):
1) Захватить текущее значение через аргумент по умолчанию (самый простой и распространённый прием):
funcs = []
for i in range(5):
funcs.append(lambda i=i: i)
print([f() for f in funcs]) # выведет [ 0,1,2,3,4 ][\;0,1,2,3,4\;][0,1,2,3,4]
2) Использовать фабрику замыканий:
def make(x):
return lambda: x
funcs = []
for i in range(5):
funcs.append(make(i))
3) Использовать functools.partial (явная привязка аргумента):
from functools import partial
funcs = []
for i in range(5):
funcs.append(partial(lambda x: x, i))
4) Синтаксический вариант через генератор/срез:
funcs = [lambda i=i: i for i in range(5)]
Что стоит избегать / на что обращать внимание:
- Не полагайтесь на «немедленное» запоминание значения при создании лямбд в цикле — это частая ловушка.
- Будьте осторожны с захватом изменяемых объектов (списков, словарей): изменения после создания замыкания будут видны внутри него.
- В Python 3 переменная цикла в списковом выражении не «протекает» наружу, но проблема позднего связывания замыкания остаётся.
Вывод: либо явно связывайте значение при создании (через аргумент по умолчанию/фабрику/partial), либо избегайте создания лямбд, которые полагаются на внешний изменяющийся контекст.
19 Мар в 12:55
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир