Python 求和,为什么不支持字符串?
Python有一个内置的函数叫做sum
,它的作用其实可以理解为:
def sum2(iterable, start=0):
return start + reduce(operator.add, iterable)
这个函数适用于除了字符串以外的所有参数类型。它可以用来处理数字和列表,比如:
sum([1,2,3], 0) = sum2([1,2,3],0) = 6 #Note: 0 is the default value for start, but I include it for clarity
sum({888:1}, 0) = sum2({888:1},0) = 888
那么,为什么字符串被特别排除在外呢?
sum( ['foo','bar'], '') # TypeError: sum() can't sum strings [use ''.join(seq) instead]
sum2(['foo','bar'], '') = 'foobar'
我记得在Python的讨论组里有人提到过这个原因,所以如果能给个解释或者链接到相关讨论的帖子就好了。
编辑:我知道标准的做法是用"".join
。我的问题是,为什么不允许用sum
来处理字符串,而对列表却没有这样的限制。
编辑 2:虽然我觉得在得到这么多好答案的情况下,这个问题可能不太必要,但我还是想问:为什么sum
可以在包含数字或列表的可迭代对象上使用,但在包含字符串的可迭代对象上却不行呢?
8 个回答
17
这是源代码链接:http://svn.python.org/view/python/trunk/Python/bltinmodule.c?revision=81029&view=markup
在builtin_sum函数里,有一段代码:
/* reject string values for 'start' parameter */
if (PyObject_TypeCheck(result, &PyBaseString_Type)) {
PyErr_SetString(PyExc_TypeError,
"sum() can't sum strings [use ''.join(seq) instead]");
Py_DECREF(iter);
return NULL;
}
Py_INCREF(result);
}
所以……这就是你的答案。
代码里明确检查了这个情况,并且拒绝了它。
27
其实你可以用 sum(..)
来连接字符串,只要你用对了开始的对象!当然,如果你已经能做到这一点,那说明你也已经懂得怎么用 "" .join(..)
了……
>>> class ZeroObject(object):
... def __add__(self, other):
... return other
...
>>> sum(["hi", "there"], ZeroObject())
'hithere'
49
Python不太鼓励你用“加法”来处理字符串。正确的做法是把它们连接起来:
"".join(list_of_strings)
这样做速度更快,而且占用的内存也少。
这里有个简单的性能测试:
$ python -m timeit -s 'import operator; strings = ["a"]*10000' 'r = reduce(operator.add, strings)'
100 loops, best of 3: 8.46 msec per loop
$ python -m timeit -s 'import operator; strings = ["a"]*10000' 'r = "".join(strings)'
1000 loops, best of 3: 296 usec per loop
补充一下(回应提问者的补充):至于为什么字符串会被“特别提到”,我觉得这主要是为了优化常见的情况,同时也是为了推广最佳实践:用''.join来连接字符串会快得多,所以明确禁止在sum
中使用字符串,可以让新手更容易理解这一点。
顺便说一下,这个限制已经存在“很久”了,也就是自从sum
作为内置函数被添加以来(修订版 32347)