Замыкания в Python: почему lambda в цикле возвращают последнее значение

Замыкания в Python: почему lambda в цикле возвращают последнее значение

@python_quiz

Разберем этот квиз

Код в квизе:

python

Коротко о результате

  • При вызове этот фрагмент выведет: [2, 2, 2] [0, 1, 2]

Пояснение — что именно происходит и почему

  • В f1 мы создаём список лямбд, каждая из которых возвращает значение переменной i без явной фиксации в момент создания. Все лямбды захватывают одну и ту же переменную i (замыкание по имени). К моменту, когда мы вызываем эти функции, цикл уже завершился, и i имеет последнее значение 2. Поэтому каждая lambda из f1 возвращает 2.
  • В f2 используется распространённый идиоматический приём: аргумент по умолчанию i=i. При создании каждой лямбды текущее значение i присваивается дефолтному параметру функции, то есть фиксируется. В результате каждая лямбда хранит своё значение: 0, 1, 2 соответственно.

Демонстрация (выполните в своём интерпретаторе)

python

Разбор вариантов (анализ ответов)

  • "Выведется: [2, 2, 2] [0, 1, 2]" — совпадает с наблюдаемым поведением. Первый список содержит три одинаковых значения (последнее значение i), второй — фиксированные значения через аргумент по умолчанию.
  • "Выведется: [0, 1, 2] [0, 1, 2]" — неверно, потому что без фиксации через аргумент по умолчанию все лямбды в первом списке ссылаются на одну переменную i.
  • "Выведется: [2, 2, 2] [2, 2, 2]" — неверно, потому что второй список использует аргумент по умолчанию и фиксирует разные значения.
  • "Будет выброшено исключение" — неверно: код корректен и исключений не вызывает.

Альтернативные способы получить фиксированные значения

  • Использовать фабрику функций:
python
  • Использовать functools.partial:
python

Выводы — что запомнить

  • Замыкание в Python захватывает переменные по ссылке (имя), а не по значению. Если переменная меняется после создания лямбд, все замыкания увидят её актуальное значение.
  • Часто используемый приём для "фиксации" текущего значения — передача его как аргумента по умолчанию (lambda i=i: i) или создание замыкания через функцию-фабрику.
  • Этот нюанс — частая ловушка при создании функций в циклах; знание его помогает избежать неожиданных результатов.

Report Page