Рассмотрите этот Python-кейс: "funcs = [lambda: i for i in range(3)]; print([f() for f in funcs])" — объясните результат и предложите варианты, как получить ожидаемое [0,1,2]
Результат — [2,2,2][2,2,2][2,2,2]. Почему: лямбда-функции замыкают переменную iii по ссылке (late binding), а не её текущее значение. После завершения цикла переменная iii равна последнему значению итерации (222), поэтому при вызове каждой лямбды берётся это значение. Варианты получения ожидаемого [0,1,2][0,1,2][0,1,2]: 1) Захват значения через аргумент по умолчанию ``` funcs = [lambda i=i: i for i in range(333)] print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2]
``` 2) Фабричная функция (замыкаем переданный параметр) ``` def make(j): return lambda: j funcs = [make(i) for i in range(333)] print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2]
``` 3) Немедленно вызываем лямбду, возвращающую другую лямбду ``` funcs = [(lambda x: (lambda: x))(i) for i in range(333)] print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2]
``` 4) Использовать functools.partial ``` from functools import partial funcs = [partial(lambda x: x, i) for i in range(333)] print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2]
``` Любой из этих подходов сохраняет текущее значение iii при создании каждой функции.
Варианты получения ожидаемого [0,1,2][0,1,2][0,1,2]:
1) Захват значения через аргумент по умолчанию
```
funcs = [lambda i=i: i for i in range(333)]
print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2] ```
2) Фабричная функция (замыкаем переданный параметр)
```
def make(j):
return lambda: j
funcs = [make(i) for i in range(333)]
print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2] ```
3) Немедленно вызываем лямбду, возвращающую другую лямбду
```
funcs = [(lambda x: (lambda: x))(i) for i in range(333)]
print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2] ```
4) Использовать functools.partial
```
from functools import partial
funcs = [partial(lambda x: x, i) for i in range(333)]
print([f() for f in funcs]) # -> [0,1,2][0,1,2][0,1,2] ```
Любой из этих подходов сохраняет текущее значение iii при создании каждой функции.