python之迭代器、生成器

迭代器

迭代是访问集合元素的方式之一,除了迭代器外还可以通过下标运算符来访问

基本概念

迭代器是一个可以记住遍历位置的对象,迭代器的对象从集合的第一个元素访问,直到所有元素被访问结束,迭代器只能往前不能后退。基本方法是iter()和next()
字符串、列表和元组都可以创建迭代器。注意:可迭代对象还有处于打开状态的files,sockets

1
2
3
list = [1,2,3,4]
it = iter(list)#创建迭代器
print(next(it))#输出迭代器的下一个元素

迭代器内部有一个状态,这个状态是用于记录当前迭代的位置,以便下次迭代的时候获取正确的元素

迭代器对象可以使用常规的for语言遍历或者next函数
1
2
3
4
5
6
7
8
9
10
11
12
13
list = [1,2,3,4]
it = iter(list)#创建迭代器
for x in it:
print(x)
#或者
import sys #引入sys模块
list = [1,2,3,4]
it = iter(list)#创建迭代器
while True:
try:
print(next(it))
except StopIteration:#该异常用于标识迭代的完成,防止出现无限循环情况
sys.exit()
把类作为迭代器使用

把类作为迭代器使用需要实现两个方法iter()和next(),看到这两个方法的形式,你还记得前面学过的init()吗(用于初始化)
iter()函数返回一个特殊的迭代器对象,这个对象实现了next()方法并通过StopIteration异常标识迭代的完成。
next()方法会返回下一个迭代器对象,如果容器中没有更多的元素了,则抛出异常。
创建一个返回数字的迭代器,初始值为1,逐步增加1,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
Class Getnumber:
def _iter_(self):
self.a = 1
return self
def _next_(self):
x = self.a
self.a += 1
return x
getnumber = Getnumber()
myiter = iter(getnumber)

print(next(myiter))
print(next(myiter))

生成器

基本概念

使用了yield的函数称为生成器,生成器是一个返回迭代器的函数(一个特殊的迭代器),只能用于迭代操作,返回数据时会使用yield语句,不需要上面两个方法了。
在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next方法时从当前位置继续运行。
调用一个生成器函数,返回是一个迭代器对象(不需要return了)。

对比是否用yield实例

使用yield斐波那契

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import sys

def fibonacci(n, w = 0):
a, b, counter = 0, 1, 0
while True:
if(counter > n):
return
yield a
a, b = b, a + b
print('%d, %d' %(a, b))
counter += 1
f = fibonacci(10,0) # f是一个由生成器返回的迭代器

while True:
try:
print(next(f), end = " ")
except :
sys.exit()

不使用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)

休息一下,喝杯咖啡,继续创作