Python 求和,为什么不支持字符串?

61 投票
8 回答
72885 浏览
提问于 2025-04-16 03:02

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

撰写回答