为何functools.reduce可对列表应用operator.eq,却无法处理对应map对象?
为什么
functools.reduce无法处理map(operator.eq, 可迭代对象)生成的map对象? 一、第一个代码“无效”的根本原因
先看这段代码:
import operator import functools iterable = [1, 2, 3] mapped = map(operator.eq, iterable) print(type(mapped)) # <class 'map'> functools.reduce(operator.eq, mapped)
问题出在map(operator.eq, iterable)的用法错误:
operator.eq是二元函数,需要接收两个参数才能返回布尔值(比如operator.eq(1,2)等价于1==2)。map函数会将iterable中的每个元素作为唯一参数传给operator.eq,此时operator.eq不会执行比较,而是返回一个偏应用函数(比如operator.eq(1)等价于lambda x: x == 1,等待接收第二个参数)。
也就是说,mapped这个map对象里的元素不是布尔值,而是一个个等待参数的函数。当functools.reduce用operator.eq处理这些函数时:
- 第一步取前两个偏函数,用
operator.eq比较它们是否是同一个函数对象(显然不是,返回False); - 第二步用
operator.eq把False和第三个偏函数比较,判断布尔值和函数对象是否相等(返回False)。
这完全不是预期的“元素比较”逻辑,所以代码看起来“无效”。
二、直接用原可迭代对象的代码为何能运行(但结果意外)
这段代码能运行,但结果容易误解:
import operator import functools iterable = [True, False, False] functools.reduce(operator.eq, iterable) # 返回True
reduce的执行逻辑是累积应用二元函数,步骤如下:
- 初始取前两个元素:
True == False→ 结果为False; - 用第一步的结果和第三个元素比较:
False == False→ 结果为True。
最终返回True,但这和“所有元素是否相等”的预期不符——它不是判断所有元素是否等于第一个元素,而是依次做((a1==a2)==a3)的累积比较,所以结果容易让人误解。
三、核心问题:为什么reduce能处理原iterable,却不能处理map生成的mapped?
本质是两者的元素类型完全不同:
- 原
iterable的元素是普通值(数字、布尔值等),operator.eq可以接收两个普通值并返回布尔值,符合reduce对二元函数的要求(输入两个可比较的值,返回一个可继续参与运算的值)。 mapped的元素是偏应用函数,operator.eq接收两个函数对象时,比较的是函数是否为同一对象,而非执行预期的数值/布尔比较;后续用布尔值和函数对象比较时,逻辑完全偏离预期,最终结果毫无意义,所以看起来“无法应用”。
如果想让map生成可用于reduce的布尔值,你需要让operator.eq能拿到两个参数,比如要判断所有元素是否等于第一个元素,可以写成:
import operator import functools iterable = [1,1,1] # 让map给operator.eq传两个参数:第一个元素和当前元素 mapped = map(operator.eq, iterable, [iterable[0]]*len(iterable)) print(functools.reduce(operator.and_, mapped)) # 返回True,判断所有元素等于第一个元素
内容的提问来源于stack exchange,提问作者user2138149
相关产品推荐
相关产品推荐

