Hello World
1.6K subscribers
71 photos
6 videos
3 files
161 links
Be so good that you cannot be ignored. And then, go one step beyond.
Download Telegram
Замыкания с поздним связыванием.

Один из распространенных источников путаницы в Python — способ связывания переменных в замыканиях (closures).

Например, вы пишите:
def create_multipliers():
return [lambda x: i * x for i in range(5)]


for multiplier in create_multipliers():
print(multiplier(2), end=" ... ")
print()


Что вы ожидаете:
Out [0]: 0 … 2 … 4 … 6 … 8 …


Что происходит на самом деле:
Out [0]: 8 … 8 … 8 … 8 … 8 …


Создаются пять функций, и все они умножают x на 4. Почему?

📌В языке Python замыкания имеют позднее связывание
📌Значения переменных, использованных в замыканиях, определяются в момент вызова внутренней функции

🔎В нашем примере, когда вызывается любая из возвращаемых функций, значение переменной i определяется с помощью окружающей области видимости в момент вызова. К этому моменту цикл завершает свою работу и i получает итоговое значение равное четырем.

#closures
Замыкания с поздним связыванием.

Недавно мы выяснили как работает позднее связывание в замыканиях в Python. Теперь попробуем устранить проблему, которая возникала при создании замыкания.

Наиболее общее решение, возможно, станет костылем. Из-за поведения Python при определении аргументов по умолчанию для функций, вы можете создать замыкание, которое немедленно связывается со своими аргументами про помощи аргумента по умолчанию:
def create_multipliers():
return [lambda x, i=i : i * x for i in range(5)]


Либо воспользоваться functools.partial():
from functools import partial
from operator import mul

def create_multipliers():
return [partial(mul, i) for i in range(5)]


В таком случае,
Out [0]: 0 … 2 … 4 … 6 … 8 …

#closures