Лямбда и замыкания в цикле Python

Лямбда и замыкания в цикле Python

@python_quiz

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

Коротко: небольшой фрагмент кода с лямбда-функциями в списковом включении часто неожиданно возвращает одно и то же значение для всех функций. Ниже объясню почему так происходит и как этого избежать.

Код задачи

python

Что происходит и почему

  • В лямбдах используются переменные из внешней области видимости — это называется замыканием.
  • Лямбда не захватывает *значение* переменной в момент создания, она захватывает ссылку на саму переменную.
  • После завершения прохода по range(3) последним значением переменной i становится 2. Все лямбды ссылаются на ту же самую переменную i, поэтому при вызове они возвращают текущее (финальное) значение — 2.

Демонстрация (поведение при запуске):

python

> Вывод: 2 2

Замечание о версии Python: в Python 3 list comprehension создаёт собственную локальную область видимости для переменной цикла, но лямбды внутри всё равно замыкают эту переменную. Поэтому итоговое поведение (все функции возвращают последнее значение) сохраняется.

Анализ вариантов (кратко)

  • "Выведет: 0 2" — такое ожидание возникает, если думать, что каждая лямбда захватывает текущее значение i. Но лямбда захватывает переменную, а не её моментальное значение.
  • "Выведет: 2 2" — именно то, что происходит: все функции возвращают последнее значение переменной цикла.
  • "Выведет: 0 1" — невозможно в данном фрагменте, потому что к моменту вызова обе функции смотрят на одну и ту же переменную.
  • "Ошибка выполнения" — ошибка не возникает; код корректен и отработает, вернув описанное значение.

Как получить "ожидаемое" поведение (каждая функция — своё значение)

Если нужно, чтобы каждая лямбда запоминала текущее значение i при создании, есть несколько распространённых способов:

1) Использовать значение по умолчанию аргумента функции:

python

2) Сделать фабрику функций:

python

3) Использовать functools.partial (аналогично фиксированию аргумента):

python

Все три приёма создают для каждой функции собственное закреплённое значение, вместо общей переменной цикла.

Вывод

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

Report Page