迭代器
迭代是访问集合元素的方式之一,除了迭代器外还可以通过下标运算符来访问
基本概念
迭代器是一个可以记住遍历位置的对象,迭代器的对象从集合的第一个元素访问,直到所有元素被访问结束,迭代器只能往前不能后退。基本方法是iter()和next()
字符串、列表和元组都可以创建迭代器。注意:可迭代对象还有处于打开状态的files,sockets
1 | list = [1,2,3,4] |
迭代器内部有一个状态,这个状态是用于记录当前迭代的位置,以便下次迭代的时候获取正确的元素
迭代器对象可以使用常规的for语言遍历或者next函数
1 | list = [1,2,3,4] |
把类作为迭代器使用
把类作为迭代器使用需要实现两个方法iter()和next(),看到这两个方法的形式,你还记得前面学过的init()吗(用于初始化)
iter()函数返回一个特殊的迭代器对象,这个对象实现了next()方法并通过StopIteration异常标识迭代的完成。
next()方法会返回下一个迭代器对象,如果容器中没有更多的元素了,则抛出异常。
创建一个返回数字的迭代器,初始值为1,逐步增加1,如下:
1 | Class Getnumber: |
生成器
基本概念
使用了yield的函数称为生成器,生成器是一个返回迭代器的函数(一个特殊的迭代器),只能用于迭代操作,返回数据时会使用yield语句,不需要上面两个方法了。
在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next方法时从当前位置继续运行。
调用一个生成器函数,返回是一个迭代器对象(不需要return了)。
对比是否用yield实例
使用yield斐波那契
1 | import sys |
不使用yield斐波那契,(注释掉yield)函数只是简单执行,没有返回迭代器f
什么情况需要使用yield
划重点减少大内存的使用,举例:当我们调用函数返回一个很大的list时,一般情况是得到一个很大的list之后再去使用,这样就会非常占用内存,但是实际上我们使用的是list的遍历(list的迭代器),不需要得到完整的list,所以我们可以让这个函数每次只返回一个迭代器的一个计算结果,这个时候yield就很有用。
使用生成器不仅可以节省内存和CPU,还可以用更少的代码实现相似的功能
题外话:还记得C++如何优化斐波那契求解,传统的C++求解斐波那契会递归很多次,产生递归栈,最后因为栈溢出崩溃,优化递归部分以解决重复计算问题,优化算法,从下往上计算,根据f(0),f(1)得到f(2),再有f(1)和f(2)得到f(3)