对于Python初学者来说,列表(list)迭代器、生成器,是比较容易混淆的概念,我之前也是处于一种半迷糊的状态,所以打算好好整理一番,搞清楚其异同。
*
列表
列表是python的内置对象,可用来存储有序序列,并且可通过索引、切片等方式,获取任意位置的值,一旦创建,则所有元素都会进入内存。
迭代器
在Python3中,迭代器是定义了__next__()
和__iter()__
方法的对象。迭代器,在迭代过程中,会不断的调用__next()__
方法来获取下一个元素,因此迭代器所有元素并不需要完全进入内存。因此相对列表,性能得到优化,比如在读取一个几G的大文件时,使用迭代器,可以只将在读的文件内容放入内存中。然而,迭代器也有不可回溯,不可通过索引、切片获取元素这些特点。
生成器
生成器的定义形式类似于函数,然而与函数不同之处是,在其中使用了yield
关键字。一旦在函数中使用了yiled
关键字,该函数定义便转化成了一个生成器对象的定义。生成器在运行时,一旦遇到yield
就会带着yield后的值/对象,切换回调用方,直到调用其__next__()
或者send()
才会回到生成器继续执行。
1 | def g(): |
互相之间关系
从以上代码,我们可以看到生成器对象是有__iter__()
和__next__()
方法的。因此生成器也是迭代器,反之不成立。这便是生成器与迭代器之间的关系,那么迭代器与列表是什么关系呢?相信这是一个困扰了许多人的问题。我们先来查看一些列表的方法。
1 | 1,2,3] list_obj = [ |
可以看到,我们定义的列表对象list_obj
只有__iter__()
方法而没有__next__()
方法,所以我们可以断定列表对象只是一个有__iter()__
方法的可迭代对象,并不是一个迭代器。那么列表和迭代器究竟是怎样的关系。我们更近一步的查看
1 | list_obj.__iter__() |
不难发现,列表对象的__iter__()
方法所返回的对象是一个迭代器。
其实也正是因为这个原因,使得类似于列表这样许多可迭代对象(如set,tuple等)都可以使用for...in...
语句进行迭代。
for…in…
实际上for...in...
语句是一个对可迭代对象进行遍历的语法糖,其内部实现是首先调用可迭代对象的__iter()__
方法获取其相应迭代器对象,然后不断调用该迭代器的__next__()
方法,直到遇到StopIteration
异常,然后停止迭代,完成遍历。
过程如下
1 | 1,2,3] list_obj = [ |
最后,我们来优雅地写一个斐波那契数列吧。
1 | def fab(max): |
若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章