Замыкания и default-аргументы в lambda (Python)

Замыкания и default-аргументы в lambda (Python)

@python_quiz

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

Коротко: что делает код и почему он выводит именно этот результат.

Условие (код)

python

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

Что здесь важно — позднее связывание и фиксация значения

В Python замыкания захватывают переменные, а не их значения. Если бы мы написали lambda без параметра по умолчанию, например lambda: i*2, то все лямбда-функции ссылались бы на одну и ту же переменную i, и при вызове уже после завершения цикла i имела бы последнее значение.

При использовании lambda x=i: ... значение текущего i присваивается параметру x в момент создания лямбды. То есть default-аргумент фиксирует (байндит) текущее значение, избегая эффектов позднего связывания.

Демонстрация контрастного поведения

Пример с фиксацией (исходный код):

python

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

python

Разбор вариантов ответов (почему они могли бы появиться)

  • "[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-аргументы, можно:

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

Вывод

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

Report Page