【要点抢先看】
【妹子说】这一节的标题名称看起来比较陌生啊。 对,这一节很pythonic,是很有特色也非常重要的知识点。敲黑板! Python中有一类工具叫做迭代工具,他们能从左至右扫描对象。这包括了for循环、列表解析、in成员关系测试以及map内置函数等。 而可迭代对象,顾名思义就是可以用在上述迭代工具环境中,通过一次次迭代不断产生结果的对象。 可迭代对象分为两大类,一种是实际保存的序列,即列表、元组,字符串;另一种就是我们上一节总提到的“不一次性产生所有结果列表,而是可以在for循环中按需一次产生一个结果的对象”。如:range函数返回值、zip函数返回值、enumerate函数返回值等等,与实际序列相对应,这个叫做按需产生对象的虚拟序列。 我们注意到,这一小节的标题中还有一个词叫做迭代器,他俩放在一起容易把人弄迷糊,他们之间的关系,相信你看完下面一段介绍就会很清楚了: 可迭代对象支持内置函数iter,通过对可迭代对象调用iter函数,会返回一个迭代器,而“迭代器”支持内置函数next,通过不断对其调用next方法,会依次前进到序列中的下一个元素并将其返回,最后到达一系列结果的末尾时,会引发StopIteration异常。补充说明一点,对迭代器调用iter方法,则会返回迭代器自身。 L = [2,3,4] 从这个例子中我们看到,通过iter函数将迭代对象转化成迭代器,而对迭代器调用iter函数,依然返回迭代器。 我们来完整的看看迭代过程是怎么实现的:当任何可迭代对象传入到for循环或其他迭代工具中进行遍历时,迭代工具都是先通过iter函数获得与可迭代对象对应的迭代器,然后再对迭代器调用next函数,不断的依次获取元素,并在捕捉到StopIteration异常时确定完成迭代,这就是完整的迭代过程。这也称之为“迭代协议”。 还是举例子说明,我们来模拟for循环如何处理内置可迭代对象-----内置类型列表L: L = [2,3,4] 在这个手动模拟迭代的过程中,先把可迭代对象转换成迭代器,然后用next方法进行手动迭代,迭代到最后出现StopIteration异常退出。 与手动迭代的示例过程相对应,下面是用for循环进行自动迭代的过程,这个大家都很熟悉。 L = [2,3,4] 再举几个典型的例子 文件对象 open函数返回的已打开的文件对象,也是可以一行一行的读取,直至文件结束,那很显然,他也是可迭代对象。 f = open('myfile.txt') 从这个例子中我们可以看出,文件对象的迭代器就是他自己。即文件对象既是迭代器,又是可迭代对象。我们还是用上面的手动模拟迭代的方式来一探究竟 f = open('myfile.txt') 对应的,直接用for循环来进行自动迭代 f = open('myfile.txt') 之前我们提到过,这是读取文件的最佳方式,首先是简单、运行速度快,并且从内存使用情况而言也是最好的。让我们对比一下较为原始的readlines方法, f = open('myfile.txt') 对比来看,虽然readlines方法在功能上可用,但从内存上来看,非常糟糕,他是一次性把整个文件加载到内存,如果文件太大,以至于计算机内存不够,甚至不能够工作。而我们的迭代器版本则不然,迭代器是按需,一次只读取一行,因此对内存爆炸问题有了很好的免疫。 字典类型 文件和列表对象都是实际的序列,他所迭代的就是他的实际内容,那字典呢?字典也是一种可迭代对象,但是他的迭代器却比较特殊。我们看看手动模拟迭代过程的例子: D = {'a':1, 'b':2, 'c':3} 同样,在for循环中自动迭代的例子如下: D = {'a':1, 'b':2, 'c':3} 因此不难看出,字典也是一个可迭代对象,字典有一个迭代器,在迭代环境中,会每次自动地返回一个键。 而需要补充的是,字典拥有不同视图的可迭代对象,这里就不详细一一展开了,看看几个例子,分别是各自不同视图下的可迭代对象和迭代器,他们也是一次产生一个结果项,而不是在内存中一次产生全部结果列表。 D = {'a':1,'b':2,'c':3} 再举两个我们上一节提到的例子:range函数和enumerate函数 range函数的返回值是一个可迭代对象,同理利用iter方法也可以得到他的迭代器 R = range(5) enumerate方法返回的也是可迭代对象,他的迭代器就是他自身 E = enumerate('spam') 可迭代对象按照需求,一次只返回一个结果,而不是一口气一次性的返回一个对象列表,因此我们必须把可迭代对象包裹在一个list调用中,从而才能一次性看到它们所有的值。 print(list(enumerate('spam'))) |
|