Вопрос с собеседования · Python

Почему лямбды, созданные в цикле, возвращают одно и то же значение?

MiddleФункции
Ещё спрашивают так:
  • Что такое позднее связывание в замыканиях Python?
Коротко

Замыкание захватывает переменную, а не её значение: значение читается в момент вызова. К моменту вызова цикл закончился, и все лямбды видят последнее значение i. Исправление — зафиксировать значение: аргумент по умолчанию (lambda i=i: i) или functools.partial.

  • [lambda: i for i in range(3)] → все возвращают 2
  • Значения по умолчанию вычисляются при определении функции — здесь это и нужно
  • Та же проблема с колбэками в цикле (кнопки GUI, обработчики)

А ещё Отличие от Java: там лямбда захватывает значение effectively final переменной

Подробно

funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])        # [2, 2, 2]

funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs])        # [0, 1, 2]

from functools import partial
funcs = [partial(lambda x: x, i) for i in range(3)]

Почему. Замыкание хранит ссылку на ячейку (cell) переменной внешней области. Все лямбды ссылаются на одну ячейку i; при вызове каждая читает её текущее значение.

Это связывание по имени — то же правило LEGB, что и для обычных функций. Связь с ловушкой изменяемого аргумента по умолчанию обратная: там «раннее» вычисление по умолчанию мешает, здесь — помогает.

Что хотят услышать

  • Захват переменной, а не значения.
  • Два способа исправить.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Замыкание видит переменную, а не значение; лечится через i=i или partial
  • ✗Это ошибка интерпретатора, исправленная в Python 3.12: в новых версиях лямбды сохраняют значение i
  • ✗Лямбды копируют значение i в момент создания, а одинаковый результат даёт кэш интерпретатора
  • ✗Нужно объявить i как global внутри лямбды, тогда каждая получит своё значение

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования