Это происходит потому, что все элементы списка ссылаются на одну функцию, конечную из цикла. Новые функции не создаются.
Это не так, достаточно добавить вывод id(func)
, и увидеть что id
каждый раз выводится разный, значит и объекты функций разные. Или после цикла вывести на печать список, получится что-то такое, видно, что id разные:
[<function func at 0x7fae88593d90>, <function func at 0x7fae884b7880>, <function func at 0x7fae884b7be0>, <function func at 0x7fae884b7c70>, <function func at 0x7fae884b7d00>, <function func at 0x7fae884b7d90>, <function func at 0x7fae884b7e20>, <function func at 0x7fae884b7eb0>, <function func at 0x7fae884b7f40>, <function func at 0x7fae882b4040>]
Причина описанного поведения не в том, что функция одна и та же, а в том что все созданные функции обращаются они к одной и той же глобальной переменной, поэтому и поведение у них одно и то же.
Каждая созданная функция не запоминает значение глобальной переменной x
из прошлого, она при вызове обращается к самой этой переменной, с актуальным ее значением на момент вызова, после цикла это значение равно 9.
Можно обернуть функцию в лямбду, передав текущее значение x
через параметр по умолчанию:
def func(arg, x):
return x+arg
funcs = []
for x in range(10):
funcs.append(lambda arg, x=x: func(arg, x))
print(funcs[2](1)) # Вывод: 3
Более красивый вариант - вместо лямбды использовать functools.partial
:
funcs.append(functools.partial(func, x=x))
Или сделать функцию - фабрику функций, которая будет создавать экземпляр функции с заданным значением x
, и x
будет браться из локальной переменной внешней функции (на момент вызова, в котором была создана внутренняя функция):
def function_factory(x):
def func(arg):
return x+arg
return func
funcs = []
for x in range(10):
funcs.append(function_factory(x))
print(funcs[2](1)) # Вывод: 3