所以我从官方文档中得到了这些例子。 https://docs.python.org/2/library/timeit.html
究竟是什么让第一个例子(生成器表达式)慢于第二个(列表推导)?
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
>>> timeit.timeit('"-".join([str(n) for n in range(100)])', number=10000)
0.7288308143615723
答案 0 :(得分:17)
str.join
方法将其可迭代参数转换为列表(如果它不是列表或元组)。这使得连接逻辑可以多次遍历项目(它会通过一次计算结果字符串的大小,然后是第二次通过来实际复制数据)。
您可以在the CPython source code中看到这一点:
PyObject *
PyUnicode_Join(PyObject *separator, PyObject *seq)
{
/* lots of variable declarations at the start of the function omitted */
fseq = PySequence_Fast(seq, "can only join an iterable");
/* ... */
}
C API中的PySequence_Fast
函数就是我所描述的。它将任意迭代转换为列表(主要通过调用它上面的list
),除非它已经是列表或元组。
将生成器表达式转换为列表意味着生成器的通常好处(较小的内存占用和可能的短路)不适用于str.join
,因此(小)额外的发电机的开销使其性能变差。