🖥 Расскажите про замыкания. Какая проблема возникает при создание нескольких функций внутри одного контекста?



Когда вы определяете функцию внутри другой функции и используете локальные переменные внешней функции во вложенной, вы создаете замыкание. Время жизни этих переменных "продляется" в особой области видимости enclosing даже после завершения работы внешней функции. Пример: make_adder возвращает функцию-прибавлятор. Объект из переменной a будет жить и работать даже после выхода из make_adder:



def make_adder(a):

def adder(x):

return a + x

return adder



plus_5 = make_adder(5)

print(plus_5(3)) # 8




Здесь я хочу коснуться одной популярной проблемы. Дело в том, что если мы создадим несколько функций внутри одного контекста, то они будут разделять одну область видимости enclosing. Рассмотрим пример создания трех функций в цикле:



def make_adders():

adders = []

for a in range(3):

def adder(x):

return a + x

adders.append(adder)

return adders



adders = make_adders()

for adder in adders:

print(adder(2)) # 4 4 4




Вместо функций прибавляющих разные числа от 0 до 2, мы получили 3 одинаковых функции, потому что внутри себя они поддерживают ссылку на одну и ту же переменную a, значение которой останется равным 2 после выполнения всего цикла целиком.



Есть простой прием, помогающий "зафиксировать" значения переменной в моменте: достаточно добавить во вложенную функцию дополнительный аргумент со значением по умолчанию, равным нужной переменной a=a:



def make_adders():

adders = []

for a in range(3):

def adder(x, a=a): # FIX!

return a + x

adders.append(adder)

return adders



adders = make_adders()

for adder in adders:

print(adder(2)) # 2 3 4




Еще лучше переименовать аргумент, чтобы избежать конфликтов имен и замечаний IDE, например, так:



def adder(x, that_a=a): # FIX!

return that_a + x




@python_job_interview