Кейс (Python): Почему следующий код печатает одинаковые значения для всех замыканий и как это исправить — funcs = [] for i in range(3): funcs.append(lambda: i) print([f() for f in funcs])
Потому что лямбда-функции захватывают переменную iii по ссылке (late binding): значение iii берётся при вызове, а не при создании замыкания. После цикла iii равно 222, поэтому все функции возвращают одно и то же — вывод исходного кода будет [2,2,2][2, 2, 2][2,2,2]. Как исправить (несколько способов): 1) Привязать значение как аргумент по умолчанию: ```python funcs = [] for i in range(3): funcs.append(lambda i=i: i) print([f() for f in funcs]) # -> [0, 1, 2] ``` 2) Использовать фабрику (вложенную функцию), принимающую текущее значение: ```python def make(i): return lambda: i funcs = [] for i in range(3): funcs.append(make(i)) print([f() for f in funcs]) # -> [0, 1, 2] ``` 3) То же через списковое выражение: ```python funcs = [lambda i=i: i for i in range(3)] print([f() for f in funcs]) # -> [0, 1, 2] ``` Любой из этих подходов сохраняет текущее значение iii при создании замыкания, а не при вызове.
Как исправить (несколько способов):
1) Привязать значение как аргумент по умолчанию:
```python
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs]) # -> [0, 1, 2]
```
2) Использовать фабрику (вложенную функцию), принимающую текущее значение:
```python
def make(i):
return lambda: i
funcs = []
for i in range(3):
funcs.append(make(i))
print([f() for f in funcs]) # -> [0, 1, 2]
```
3) То же через списковое выражение:
```python
funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs]) # -> [0, 1, 2]
```
Любой из этих подходов сохраняет текущее значение iii при создании замыкания, а не при вызове.