Недавно я начал играть с Python, и я столкнулся с чем-то особенным в работе закрытия. Рассмотрим следующий код:
adders=[0,1,2,3]
for i in [0,1,2,3]:
   adders[i]=lambda a: i+a
print adders[1](3)
Он создает простой массив функций, которые принимают один вход и возвращают этот ввод, добавленный рядом. Функции строятся в цикле for, где итератор i работает от 0 до 3. Для каждого из этих чисел создается функция lambda, которая захватывает i и добавляет ее к входу функции. Последняя строка вызывает вторую функцию lambda с 3 в качестве параметра. К моему удивлению, выход был 6.
Я ожидал a 4. Мои рассуждения были: в Python все является объектом, и поэтому каждая переменная имеет важное значение для указателя на него. При создании закрытий lambda для i я ожидал, что он сохранит указатель на целочисленный объект, на который в данный момент указывает i. Это означает, что когда i назначается новый целочисленный объект, он не должен влиять на ранее созданные закрытия. К сожалению, проверка массива adders в отладчике показывает, что это так. Все функции lambda относятся к последнему значению i, 3, что приводит к возврату adders[1](3) 6.
Что заставляет меня задуматься о следующем:
- Что точно фиксируют замыкания?
-  Каков самый элегантный способ убедить функции lambdaдля захвата текущего значенияiтаким образом, чтобы это не повлияло, когдаiизменит его значение?
