Что фиксируют замыкания лямбда-функций?Python

Программы на Python
Anonymous
Что фиксируют замыкания лямбда-функций?

Сообщение Anonymous »

Недавно я начал экспериментировать с Python и обнаружил нечто странное в том, как работают замыкания. Рассмотрим следующий код:

Код: Выделить всё

adders = [None, None, None, None]

for i in [0, 1, 2, 3]:
adders[i] = lambda a: i+a

print adders[1](3)
Он создает простой массив функций, которые принимают один ввод и возвращают этот ввод, добавленный числом. Функции создаются в цикле for, где итератор i работает от 0 до 3. Для каждого из этих чисел создается лямбда функция, которая захватывает i и добавляет его во входные данные функции. Последняя строка вызывает вторую лямбда-функцию с 3 в качестве параметра. К моему удивлению, результат оказался 6.
Я ожидал 4. Я рассуждал так: в Python все является объектом, и поэтому каждая переменная является указателем на него. Создавая замыкания лямбда для i, я ожидал, что он сохранит указатель на целочисленный объект, на который в данный момент указывает i. Это означает, что когда я назначил новый целочисленный объект, это не должно влиять на ранее созданные замыкания. К сожалению, проверка массива adders в отладчике показывает, что это так. Все лямбда-функции ссылаются на последнее значение i, 3, в результате чего adders[1](3) возвращает 6.
Это заставляет меня задуматься о следующем:
  • Что именно фиксируют замыкания?
  • Какой самый элегантный способ убедить лямбда-функции фиксировать текущее значение i таким образом, что это не будет затронуто, когда i изменит свое значение?
Более доступную и практичную версию вопроса, специфичную для случая, когда используется цикл (или понимание списка, выражение-генератор и т. д.), см. в разделе Создание функций (или лямбда-выражений) в цикле (или понимании). Этот вопрос направлен на понимание основного поведения кода в Python.
Если вы пришли сюда, пытаясь решить проблему с созданием кнопок в Tkinter, попробуйте tkinter создать кнопки в аргументах команды цикла for, чтобы получить более конкретные советы.
Смотрите, что именно содержится в obj.__closure__? технические подробности о том, как Python реализует замыкания. См. В чем разница между ранним и поздним связыванием? для обсуждения соответствующей терминологии.

Вернуться в «Python»