#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, то вы не хотите складывать результаты вместе. Вам нужна функциональная композиция, и идите, прочитайте ответ Чепнера.