python sum(list)和reduce(lambda x,y:x + y,list)之间有差异吗?

时间:2018-08-07 01:11:58

标签: python python-2.7 list sum reduce

img { display: block; border-radius: 100px; border: 1px solid #fff; width: 80px; height: 80px; margin: 30px auto 0; box-shadow: 0px 0px 4px rgba(0,0,0,0.7); margin-top: 0px; } sum(list)之间有什么区别

reduce(lambda total , element : total + element, list)

2 个答案:

答案 0 :(得分:3)

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中将其删除…),但是它确实会引发一个标志,使我可以更加仔细地查看我的代码(或其他人的代码),以查看是否存在更Python化的编写方式,而且经常有。


reduce可以做除求和以外的其他事情。

例如,假设您要用一堆数字创建一个数字:

def fromdigits(*digits, base):
    return reduce(lambda acc, digit: base*acc + digit), digits, 0)

尝试用sum来写。

(尽管我敢打赌,这个例子只是让Guido哭了,但这是我想到的第一件事不是关于树木的……)

答案 1 :(得分:1)

从逻辑上讲,sum(list)reduce(lambda total, element: total + element, list, 0)之间没有区别(请注意,默认值作为第三个参数传递给reduce)。

sum有一些细微差别;它有一个特殊的快速路径来求和较小的整数(当总和可以放入C long时),它避免了每次添加Python级别的函数调用,并且即使求和str对象也是如此给定start的值''(从逻辑上没有阻止它,但是在str上使用重复加法效率极低,因此它拒绝str将用户指向{{1 }},这是连接许​​多''.join的正确方法。

str不同,sum可以与任何可加类型一起使用,只要输入中至少包含一个元素(其中reduce要求您传递一个{{1 }}值(用于任何非数字类型)。

通常,您应为此目的使用sum (或将start使用sum或将{{1} 1}} / ''.join); str的专业性较弱,速度较慢,维护人员通常认为较难理解。