sum 更清楚你的意图,而且更短。
阅读reduce 版本,我可以看到您正在减少具有某些功能的列表。然后我读了那个函数,发现它正在添加值。所以,我可以弄清楚你在总结数字。然后我可能还需要验证你是否正确实现了它。
阅读sum 版本,我立即知道您正在对数字求和,并且做得对。
sum 更快。
In [905]: %timeit sum(orderItemsMap)
173 ns ± 3.13 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [906]: %timeit reduce(lambda total , element : total +element , orderItemsMap)
601 ns ± 8.09 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
reduce 版本必须做一个通用循环,而sum 版本可以做一些优化。此外,reduce 版本必须为每对值调用您的lambda,而sum 版本可以直接跳转到__add__。而且,至少在 CPython 中,sum 对小整数求和进行了进一步优化。
sum 适用于空列表。
In [907]: sum([])
Out[907]: 0
In [908]: reduce(lambda total , element : total +element, [])
TypeError: reduce() of empty sequence with no initial value
当然,您可以通过添加第三个参数使 reduce 为空列表工作:
In [909]: reduce(lambda total , element : total +element, [], 0)
Out[909]: 0
……但这让它变得更长,更不明显。
sum 不鼓励你不小心做你不想做的事情。
In [911]: sum(["abc", "def", "ghi"])
TypeError: unsupported operand type(s) for +: 'int' and 'str'
In [912]: sum(["abc", "def", "ghi"], '')
TypeError: sum() can't sum strings [use ''.join(seq) instead]
In [913]: reduce(lambda total , element : total +element, ["abc", "def", "ghi"])
Out[913]: 'abcdefghi'
使用reduce,我只是连接了一堆字符串,这可能需要二次时间,而我真正想做的是调用''.join,这需要线性时间。
好的,CPython 3.7 和 PyPy 3.5/6.0 碰巧优化了这种情况以使其更好......但他们没有这样做,例如,元组列表。
sum 不会让 Guido 哭泣。
许多 Python 开发人员讨厌 reduce。通常的引用是“在每个reduce 内部,都有一个for 循环在努力摆脱”。或SyntaxError('Lisp needs more parentheses')。
我认为这有点极端,而且我知道我不是唯一一个在 Python 中找到了 reduce 的好用处的人(其他核心开发人员不会说服 Guido 移动它functools 而不是在 3.0 中删除它...),但它确实会引发一个标志,让我更仔细地查看我的代码(或其他人的),看看是否有更 Pythonic 的方式来编写它,并且经常在那里是。
reduce 可以做除求和以外的事情。
例如,假设您想从一堆数字中创建一个数字:
def fromdigits(*digits, base):
return reduce(lambda acc, digit: base*acc + digit), digits, 0)
尝试使用sum 编写。
(虽然我敢打赌,这个例子让 Guido 哭了,但首先想到的不是树……)