Как создать функцию как новый объект в python?
Есть код:
funcs = []
for x in range(10):
def func(arg):
return x+arg
funcs.append(func)
print(funcs[2](1))
output: 10
Он создает список из 10 функций (элементов), каждая функция должна иметь аргумент x в соответствии с индексом x.
Т.е. при вызове func[2](1) должно возвращаться 2 + 1 = 3, но возвращается 10. Это происходит потому, что все элементы списка ссылаются на одну функцию, конечную из цикла. Новые функции не создаются.
И в этом случае x = 9, 9+1 = 10.
Мне нужно чтобы у каждой функции был свой уникальный x в соответствии с циклом. Как это сделать?
Ответы (1 шт):
Это происходит потому, что все элементы списка ссылаются на одну функцию, конечную из цикла. Новые функции не создаются.
Это не так, достаточно добавить вывод 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