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