Разберите поведение замыканий в Python: funcs = [lambda: i for i in range(3)]; results = [f() for f in funcs] — почему все вызовы возвращают одно и то же значение и какие способы создать корректные независимые замыкания вы предложите

12 Ноя в 10:17
4 +4
0
Ответы
1
Коротко — потому что замыкания захватывают переменную, а не её текущее значение. В вашем примере
- вы пишете `funcs = [lambda: i for i in range(3)]` (где 333 — верхняя граница),
- всякий `lambda` ссылается на одну и ту же переменную `i`,
- после завершения цикла `i` равно последнему значению (в данном случае 222),
- поэтому `results = [f() for f in funcs]` даст [2,2,2][2, 2, 2][2,2,2].
Причина: в Python замыкание хранит ссылку на «ячейку» переменной; значение берётся при вызове (late binding), а не при создании лямбды.
Способы получить независимые замыкания
1) Привязать значение через аргумент по умолчанию:
```python
funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs]) # -> [0, 1, 2]
```
2) Фабрика функций (вложенная функция с параметром):
```python
def make(x):
return lambda: x
funcs = [make(i) for i in range(3)]
print([f() for f in funcs]) # -> [0, 1, 2]
```
3) functools.partial или любой callable, фиксирующий аргумент:
```python
from functools import partial
def id(x): return x
funcs = [partial(id, i) for i in range(3)]
print([f() for f in funcs]) # -> [0, 1, 2]
```
4) Создать локальную переменную в теле цикла (эквивалентно 1/2):
```python
funcs = []
for i in range(3):
j = i
funcs.append(lambda: j)
print([f() for f in funcs]) # -> [0, 1, 2]
```
Доп. замечание: в Python 3 переменная цикла в списковых включениях берётся в отдельной локальной области, но замыкания всё равно захватывают одну «ячейку» этой переменной, поэтому поведение с поздним связыванием остаётся — нужно явно зафиксировать значение одним из методов выше.
12 Ноя в 10:26
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир