Нещодавно я почав грати з 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
.
Я очікував 4
. Мої міркування були такі: у Python все є об'єктом, тому кожна змінна є важливим вказівником на нього. Під час створення lambda
закриття для i
, я очікував, що він збереже вказівник на цілий об'єкт, на який вказує даний момент i
. Це означає, що при i
призначенні нового цілого об'єкта він не повинен здійснювати попередньо створені закриття. На жаль, огляд adders
масиву всередині налагоджувача показує, що це так. Всі lambda
функції відносяться до останнього значенням i
, 3
, що призводить до adders[1](3)
повернення 6
.
Що змушує мене замислитися над наступним:
- Що саме фіксує закриття?
- Що є найелегантнішим способом переконати
lambda
функції захоплення поточного значенняi
таким чином, що це не вплине приi
зміні його значення?
i
залишається простір імен?
print i
після циклу не буде працювати. Але я перевірив це на собі і тепер бачу, що ти маєш на увазі - це працює. Я не мав уявлення, що змінні циклу затримуються за тілом циклу в python.
if
, with
, і try
т.д.