0前言在处理循环的时候,我们习惯使用for,while等,比如依次打印每个列表中的字符:当打印内容字节数小,将所有文件加载到内存中,再打印,没有问题。但是,如果有几千万条车辆轨迹,要求你分析其中每个客户的出行方式和交通拥堵情况,如果你在单机上处理这个事情。你可以先面对它,也可以忽略它。代码写完之后,可能会暴露一个问题:outofmemory,这在实际项目中经常遇到。这个问题提醒我们,在处理数据时,如何编写高效使用内存的程序非常重要。今天,我们将讨论如何有效地使用内存,节省内存并同时完成工作。其实Python已经准备了一个模块专门来处理这件事情。它是itertools模块。里面的几个函数的作用其实很好理解。我无意笼统地介绍它们能实现的功能,而是想分析一下这些功能背后的实现代码,它们是如何高效节省内存的,Python内核贡献者是如何写出漂亮的代码的。这很有趣,不是吗?好了,走吧。希望你喜欢这个旅程!1拼接元素itertools中的chain函数实现了元素的拼接。原型如下,参数*表示可变数量的参数链(iterables)。有点join的味道,但是比join强。它的重点是参数都是可迭代的实例。那么,chain是如何实现高效的内存节省的呢?chain的大致实现代码如下:上面的代码不难理解,chain本质上返回的是一个生成器,所以它实际上是一次读取一个元素到内存中,所以最节省内存。2将返回列表的累加汇总值逐个累加,原型:accumulate(iterable[,func,*,initial=None])应用如下:accumulate的大概实现代码如下:上面的代码,你还好吗?不同于chain的简单yield,这里稍微复杂一点。yield有点像return,所以yieldtotal这一行直接返回了一个元素,也就是iterable的第一个元素,因为这个函数任何时候返回的第一个元素都是它的第一个。又因为yield返回的是一个生成器对象,比如名字为gen,所以在next(gen)的时候,代码会执行到其中的for元素:行,而此时it的iterator已经指向了第二个元素iterable,OK,相信你明白了!3Funnelscreening是一个compress函数,功能类似于funnelfunction,所以我称之为funnelscreening,原型:compress(data,selectors)很容易看出compress返回的元素个数等于两个参数的较短列表的长度。其大致实现代码:这个函数非常有用,可以过滤扫描4段的列表,保留不符合条件的部分。原型如下:dropwhile(predicate,iterable)应用示例:实现的大概代码如下:5段过滤2次扫描List,只要满足条件,就从iterable对象中返回元素,直到条件满足不满足,原型如下:takewhile(predicate,iterable)应用示例:实现它的大概代码如下:6缺陷筛选扫描列表,只要不满足条件都保留,原型为如下:dropwhile(predicate,iterable)应用实例:实现的大概代码如下:7切片与过滤Python中常见的切片操作,例如:它们的缺陷是必须把所有的li都加载到内存中,所以它是更省内存操作islice,原型如下:islice(iterable,start,stop[,step])应用实例:实现的大致代码如下:e生成器迭代结束,做一些边界处理。8细胞分裂tee函数类似于众所周知的细胞分裂。它可以复制n个原始迭代器。原型如下:tee(iterable,n=2)应用如下。可以看出,这两个复制的迭代器是独立实现的,其代码大致如下:tee内部使用了一个队列类型deques,初始生成一个空队列,为每个复制的队列添加元素newval,产生当前调用的最左边的元素mydeque。9map变体starmap可以看作是map的变体,可以更节省内存,iterable的元素也必须是可迭代对象。原型如下:starmap(function,iterable)应用:starmap的实现细节如下:10Copyelementrepeat实现复制元素n次,原型如下:repeat(object[,times])apply如下:其实现细节大致如下:11笛卡尔积Cartesianproduct效果如下:因此,笛卡尔积的实现效果如下:其实现细节:12增强版zip组合值。如果可迭代对象的长度没有对齐,缺失值会根据fillvalue进行填充。注意:迭代一直持续到最长的可迭代对象耗尽。效果如下:它的实现细节:它使用了repeat,即在iterableobject中长度错位时,根据fillvalue来填充缺失值。理解上面代码的关键是迭代器对象(iter),next方法的特殊性:结合这个提示再理解上面代码就不会难了。
