我们都知道,遍历一个list(列表)有两种方式,一种是直接输出list的对象,还有一种是使用for去迭代。这两者的区别,我将从时间和空间两方面来考虑,为了明显一点,列表长度会很大,原因大家应该也知道。
下面的代码是一次性输出一个很长的列表。
代码运行之后先看一下内存占用。
一个Python程序,运行时占用了五百多MB内存,也是很恐怖的,如果把我的这个列表,再扩大1000倍(内存占用五百多GB,大概0.5TB),估计也只有天河可以顶住,如果再扩大10^7或者更多的话,就已经超出了64位操作系统的寻址范围2^64B = (2^10)^62^4B = (2^10)^22^4TB = 16EB。
再来看一下运行时间,如图所示。
2秒多,已经不错了,空间牺牲的也算是值了!
接下来我来演示一下用for循环遍历这个列表,代码如下。
接下来还是先看一下内存占用。
看一下内存占用,400MB不到,比之前少了一点,空间减少必然会导致时间增加,到底时间上多了多少,往下看就对了!
减少了大概170MB的空间,却增加了十几倍的时间,明明两三秒能完成的事,这个for循环遍历花了四十多秒,这显然是不值得的。
问题来了,难道大量数据进行操作真的一点办法都没有吗?
办法还是有的,大量数据,我完全可以不往内存中存放,放到文件中,需要处理的时候就一点一点处理,下面的代码就是这样先把数据写入一个临时文件,然后再读取数据。
接着还是老样子,看一下内存占用。
内存占用比原来少多了,终于可以喘口气了,下面来看一下时间的消耗。
算了,不说了,太浪费时间了。减少时间的办法也是有的,把这个大列表分成4个部分(最好是CPU有几个核心就分成几个部分),每一部分写入一个临时文件(这里可以使用多进程,每个文件相互独立,资源相互独立,不会有影响),然后读取数据的时候也可以使用多进程。
到这里为止,前面讲的东西不管你是做什么的,一定要懂!!!(不懂加群,群号加群方式见文末)之后的讲的只要Python程序员会就行了。
文章还没有结束,确实还有其他办法处理这些大量数据,这也是今天要讲的重点!
直接切入正题,我们都经常使用range这个函数,这个函数到底是个什么东西?交互式解释器输入help(range)回车就知道了。
看了help,稍微翻译一下,这是一个range object对象,这个对象会产生一个整数序列,从start(包括)到end(不包括),start默认为0,step默认为1。既然是产生一个整数序列,输出应该是一个列表。
然而并不是,这东西到底是什么呢?!因为range函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。可迭代对象就是能够用for去遍历的对象,只要一个类实现了__iter__和__next__两个魔法方法这个类实例化出来的对象就是可迭代对象。这样做的目的也正是节约了内存空间。
但是问题还是有的,range只能有规律的迭代,而且只能是整数。如果数据不是整数难道就必须创建列表了吗?并不是,该介绍接下来的主角——迭代器!迭代器的使用方法如下。
上面的代码就是调用iter创建了一个可迭代对象,然后用for遍历。
这个迭代器只能适用于逻辑比较简单的情况,如果逻辑特别复杂,必须从函数中进行迭代,该如何下手?一般人能够想到的就是定义类并实现__iter__和__next__两个魔法方法,这样做没问题,但是会显得更复杂。
Python有一个更简单的东西可以直接从函数中实现迭代,它就是生成器,下面我来演示一下在函数中使用生成器。
在函数中使用生成器,只需要使用yield关键字把需要迭代的值返回出去,然后函数收回控制权,继续执行函数本身(和return不同,return返回出去函数不会收回控制权,也不会继续执行函数体了)。
没有函数还是可以使用生成器,只不过和使用迭代器iter没有太大区别,创建生成器对象很简单,这里使用的是生成器表达式,只需要把列表推导式的中括号改成小括号。
列表推导式:a = [i for i in range(10)],a是一个列表对象。
生成器表达式:a = (i for i in range(10)),a是一个生成器对象。
本文分享自 Python机器学习算法说书人 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!