Рассмотрите фрагмент Python: funcs = [lambda: i for i in range(3)]; результаты = [f() for f in funcs]; объясните, почему результаты оказываются такими, каковы семантика замыканий в Python и как исправить код, чтобы получить [0,1,2]

9 Ноя 2025 в 21:46
22 +1
0
Ответы
1
Кратко: в Python замыкания захватывают переменные по ссылке (late binding), поэтому все лямбды в примере ссылаются на одну и ту же переменную `i`, которой после цикла присвоено последнее значение. В вашем фрагменте
funcs = [lambda: i for i in range(333)]
results = [f() for f in funcs]
вызов `results` даст [2,2,2][2, 2, 2][2,2,2], потому что после выполнения цикла `i` равно 2\,22\, (последнее значение из `range(333)`).
Как исправить (варианты):
1) Сохранить текущее значение в параметре по умолчанию:
funcs = [lambda i=i: i for i in range(333)]
results = [f() for f in funcs] # -> [0,1,2][0, 1, 2][0,1,2]
2) Использовать фабрику лямбд:
def make(j):
return lambda: j
funcs = [make(i) for i in range(333)]
results = [f() for f in funcs] # -> [0,1,2][0, 1, 2][0,1,2]
3) С помощью functools.partial:
from functools import partial
funcs = [partial(lambda x: x, i) for i in range(333)]
results = [f() for f in funcs] # -> [0,1,2][0, 1, 2][0,1,2]
Вывод: чтобы получить [0,1,2][0, 1, 2][0,1,2], нужно захватить значение `i` на момент создания функции (например, через параметр по умолчанию или фабрику).
9 Ноя 2025 в 22:08
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир