Ошибка типа: объект ‘int’ не может быть вызван при использовании reduce и lambda

#python #function #functional-programming

Вопрос:

 from functools import reduce

lists = [lambda x: x 5, lambda x: x 6, lambda x: x 7]
n = 5

print(list(reduce(lambda a, b: a(n)   b(n), lists)))
 

Я не уверен, почему я получаю ошибку «Ошибка типа: объект ‘int’ не вызывается»

Комментарии:

1. Какого вы ожидаете результата? Вы знаете, что reduce на самом деле происходит? В частности, какой тип/значение вы ожидаете a получить на каждом шаге?

2. Я ожидал, что он будет использовать функцию лямбда, которая находится в списках[]. Я думал, что окончательный результат должен быть 23

3. Но a(n) b(n) вернет int объект , который будет передан на следующую итерацию как a … так что, когда вы это сделаете some_int(n) b(n) …. вы получаете сообщение об ошибке

Ответ №1:

a и b являются обеими функциями, но b гарантируется, что это будет только функция из аргумента списка. a является результатом последнего вызова to предыдущего вызова первого аргумента to reduce . Вы хотите уменьшить lists использование композиции функций.

 >>> reduce(lambda a, b: lambda n: b(a(n)), lists)(5)
23
 

(В данном конкретном случае a(b(n)) будет работать одинаково, потому что все три функции задействованы в одной и той же коммутативной операции, поэтому композиция также коммутативна. В общем случае, однако, a привязывается к первой функции и b второй на первой итерации; после этого a привязывается к результату и b привязывается к следующей функции из списка.)

Чтобы заставить его работать с пустым списком, вам необходимо указать функцию идентификации ( lambda x: x ) в качестве начального значения, так как это идентификатор для композиции функций:

 >>> reduce(lambda a, b: lambda n: b(a(n)), [])(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: reduce() of empty sequence with no initial value
>>> reduce(lambda a, b: lambda n: b(a(n)), [], lambda x: x)(5)
5
 

Ответ №2:

reduce использует предыдущий результат вызова функции в качестве одного из входных данных для следующего вызова. Функция возвращает int значение при первом вызове, поэтому при втором вызове ее двумя аргументами являются значение int и другая функция-и значение int не является допустимым параметром для предоставленной вами функции сокращения (она ожидает две функции), поэтому вы получаете эту ошибку.

Ответ №3:

Вам нужно указать начальное значение reduce и накопить другие значения позже.

 reduce(lambda acc, b: acc   b(n), lists, 0)
 

Альтернативно, мы можем разделить это на две операции: a map и a reduce .

 reduce(lambda a, b: a   b, map(lambda f: f(n), lists), 0)
 

reduce с и 0 справедливо sum , так что мы можем сократить это до

 sum(map(lambda f: f(n), lists))
 

или, что эквивалентно

 sum(f(n) for f in lists)
 

Комментарии:

1. уменьшение(лямбда а, в: а в, сопоставление(лямбда f: f(n), списки)) не приводит к ошибке, но все равно не возвращает правильное число

2. Вопрос, сформулированный в ОП, включает в себя сложение результатов вместе. Если это нежелательное поведение, пожалуйста, отредактируйте вопрос, чтобы отразить это.

3. Мы действительно хотим добавить результаты вместе, но в операции результат должен быть 23, но при использовании вашего кода он возвращает 33

4. Если вы ожидаете 23, то вы не хотите складывать результаты вместе. Вам нужна функциональная композиция, и идите, прочитайте ответ Чепнера.