recipe section的itertools文档以本文开头:
The extended tools offer the same high performance as the underlying
toolset. The superior memory performance is kept by processing
elements one at a time rather than bringing the whole iterable into
memory all at once. Code volume is kept small by linking the tools
together in a functional style which helps eliminate temporary
variables. High speed is retained by preferring “vectorized” building
blocks over the use of for-loops and generators which incur
interpreter overhead.
问题是,如何构建发电机以避免开销?你能提供一些具有这种开销的构造不良的块的例子吗?
我决定问我什么时候回答this question,我无法确切地说链(序列,[obj])是否有超过链的开销(序列,重复(obj,1)),我应该更喜欢后者.
解决方法:
doc文本不是关于如何构造生成器以避免开销.它解释了正确编写的itertools使用代码,例如示例中提供的代码,完全避开for循环和生成器,将其留给itertools或内置收集器(如list)来使用迭代器.
举例来说,制表示例:
def tabulate(function, start=0):
"Return function(0), function(1), ..."
return imap(function, count(start))
写这个的非矢量化方式应该是:
def tabulate(function, start=0):
i = start
while True:
yield function(i)
i += 1
这个版本“会产生解释器开销”,因为循环和函数调用是在Python中完成的.
关于链接单个元素,可以安全地假设链(sequence,[obj])将(通常)更快(因为固定长度列表构造在Python中使用专门的语法和操作码进行了很好的优化.同样,链(sequence,(obj,))会更快,因为元组共享列表的优化,并且引导更小.与基准测试一样,使用python -m timeit测量比测量要好得多.
文档引用并不涉及迭代器创建的差异,例如通过选择repeat(foo,1)和[foo]之一所展示的那些.由于迭代器只生成一个元素,因此它的消耗方式没有区别.在处理可产生数百万个元素的迭代器时,文档谈论处理器和内存效率.与此相比,选择创建更快的迭代器是微不足道的,因为创建策略可以随时更改.另一方面,一旦代码被设计为使用不向量化的显式循环,在没有完全重写的情况下稍后更改可能非常困难.