Нещодавно я почав грати з 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т.д.