迭代器
我们把可以通过for…in…这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable)。
判断一个对象是否是可迭代对象,利用isinstacnce()方法:
在可迭代对象中记录每次迭代位置的是迭代器,可迭代对象通过__iter__方法提供一个迭代器,在迭代一个可迭代对象时,实际是获取该对象的迭代器,然后通过这个迭代器来获取可迭代对象中的每一个数据。
即,一个具备了__iter__方法的对象,就是一个可迭代的对象。
list、tuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。
代码如下:
class Fibonacci(object):
def __init__(self, all_num):
self.all_num = all_num
self.current_num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.current_num < self.all_num:
ret = self.a
self.a, self.b = self.b, self.a + self.b
self.current_num += 1
return ret
else:
raise StopIteration
fibo = Fibonacci(10)
for num in fibo:
print(num)
生成器
生成器是一类特殊的迭代器。
下述文字是引用:
在使用生成器实现的方式中,我们将原本在迭代器__next__方法中实现的基本逻辑放到一个函数中来实现,但是将每次迭代返回数值的return换成了yield,此时新定义的函数便不再是函数,而是一个生成器了。简单来说:只要在def中有yield关键字的 就称为 生成器
利用函数来实现生成器:
代码如下:
def create_num(all_num):
print("-----1-----")
a, b = 0, 1
current_num = 0
while current_num < all_num:
print("-----2-----")
yield a
print("-----3-----")
a, b = b, a + b
current_num += 1
print("-----4-----")
obj = create_num(10)
ret = next(obj)
print(ret)
ret = next(obj)
print(ret)
上述代码的运行结果图:
分析:
因为生成器也是迭代器,所以我们用next方法来获取每次生成的值。
第一次运行时候运行到yield后停止,然后yield 后的值作为next获取到的值,所以输出0;之后程序在yield处停止,直到下次调用next函数。
关键:
- 保存当前运行状态(断点),然后暂停执行,即将生成器(函数)挂起
- 将yield关键字后面表达式的值作为返回值返回,此时可以理解为起到了return的作用
生成器实现斐波那契数列:
代码如下:
def fib(n):
current = 0
num1, num2 = 0, 1
while current < n:
num = num1
num1, num2 = num2, num1 + num2
current += 1
yield num
return 'done'
g = fib(5)
while True:
try:
x = next(g)
print("value:%d"%x)
except StopIteration as e:
print("生成器返回值:%s"%e.value)
break
上述代码的输出结果:
上述代码的分析:
其中,next函数取不到值的时候会引发StopIteration异常,因此捕获异常,最后的返回值为生成器函数的return 值。
总结:
迭代器和生成器都可以是保存生成数据生成的代码,在需要的时候再进行生成,减少占用空间,生成器相比迭代器更为方便。
原因如下:(参考自视频教案)
利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是我们在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一类特殊的迭代器。
参考:
https://www.bilibili.com/video/BV1uJ411Y7uH?p=40