Лямбды и захват переменных в Python
@python_quizРазберем этот квиз
Коротко: при создании лямбд в цикле важно понимать, когда именно переменная, на которую они ссылаются, фиксируется. В приведенном примере одна группа лямбд захватывает переменную по ссылке (late binding), другая — фиксирует значение через значение по умолчанию аргумента.
Исходный код

Что происходит (пошагово)
- При выполнении
[lambda x: i*x for i in range(3)]в каждую лямбда-функцию записывается не текущее числовое значение i, а ссылка на переменную i из внешней области видимости. Эта переменная изменяется циклом и после завершения цикла равна 2. При последующем вызове всех лямбд i будет равно 2, поэтому каждая из них вернёт 2*5 = 10. Получаем [10, 10, 10]. - При использовании
lambda x, i=i: i*xзначение i передаётся как значение по умолчанию аргумента i в момент создания лямбды. Это фиксирует текущее значение i (0, затем 1, затем 2). При вызове каждое замкнутое значение использует свою зафиксированную копию: [0*5, 1*5, 2*5] → [0, 5, 10].
Демонстрация (ожидаемый вывод)

Анализ вариантов ответа (кратко)
- [[10, 10, 10], [0, 5, 10]] — совпадает с реальным выводом программы (объяснение выше).
- [[0, 5, 10], [0, 5, 10]] — подразумевает, что обе группы лямбд зафиксировали i при создании; это неверно для первой группы.
- Произойдет ошибка — в данном коде ошибок не возникает.
- [[10, 10, 10], [10, 10, 10]] — такое поведение случилось бы, если бы и в первой, и во второй группе использовалась поздняя привязка к одному и тому же итоговому значению i; однако вторая группа специально фиксирует значение через
i=i.
Альтернативные способы решения и паттерны
- Фабрика функций (функция-генератор замыканий):

- Использование functools.partial или operator:

- Явно передавать значение в лямбду как аргумент по умолчанию (уже в примере) — самый компактный и распространённый приём.
Выводы
- Лямбды захватывают переменные по ссылке; значение переменной будет взято при вызове, если не зафиксировать его явно.
- Для фиксации текущего значения в момент создания замыкания удобно использовать аргумент со значением по умолчанию (
i=i) или фабрику функций. - Понимание механики захвата переменных помогает избежать тонких багов при создании списка функций в цикле.