Замыкания и default-аргументы в lambda (Python)
@python_quizРазберем этот квиз
Коротко: что делает код и почему он выводит именно этот результат.
Условие (код)

Ожидаемый вывод этого фрагмента:

Что здесь важно — позднее связывание и фиксация значения
В Python замыкания захватывают переменные, а не их значения. Если бы мы написали lambda без параметра по умолчанию, например lambda: i*2, то все лямбда-функции ссылались бы на одну и ту же переменную i, и при вызове уже после завершения цикла i имела бы последнее значение.
При использовании lambda x=i: ... значение текущего i присваивается параметру x в момент создания лямбды. То есть default-аргумент фиксирует (байндит) текущее значение, избегая эффектов позднего связывания.
Демонстрация контрастного поведения
Пример с фиксацией (исходный код):

Тот же пример без фиксации:

Разбор вариантов ответов (почему они могли бы появиться)
- "[0, 2, 4]" — соответствует ситуации с использованием
lambda x=i: .... Default-аргумент фиксирует 0,1,2 соответственно, каждая функция возвращает удвоенное значение этого зафиксированного аргумента. - "[4, 4, 4]" — соответствует варианту, где лямбды не фиксируют значение, например
lambda: i*2. Все функции ссылаются на одну переменнуюi, которая после цикла равна 2, поэтому результат 2*2 для каждой из них. - "[2, 4, 6]" — это последовательность удвоенных значений 1,2,3; появилась бы, если бы диапазон был
range(1, 4)или если бы индексы начинались с 1. В текущем коде индексы идут от 0 до 2, поэтому этот вариант не соответствует. - "[0, 0, 0]" — мог бы возникнуть, если бы все лямбды фиксировали значение 0 (например, ошибочно), или если бы переменная всегда была 0 к моменту вызова. В данном коде это не так.
Альтернативные способы избежать позднего связывания
Если не хочется использовать default-аргументы, можно:
- Создать фабрику функций:

- Использовать functools.partial:

Вывод
Ключ к пониманию — различать захват переменной и фиксацию её значения. Параметр по умолчанию в лямбде используется здесь как трюк для фиксации текущего значения цикла в момент создания функции, что приводит к предсказуемому набору результатов. Это простой, идиоматичный способ избежать сюрпризов с замыканиями в Python.