首页 > 代码库 > python迭代器和生成器
python迭代器和生成器
心情有点复杂,同学和几个发小这几天都相继做了爸爸,手段都很低级,肚子搞大,唉~而我确还在组建家庭的路上,我不想太急,家里毕竟不能为我提供更多的帮助,坚持吧!
工作之余还在学习确实很累,想一锹挖个井实在太难,还是得慢慢得来,慢慢得学必定有很多的收获,坚持吧!
上海的天气好热,早上出门挤上地铁全身已湿透,晚上下班铺面而来的全是汽车尾气和热浪,坚持吧!
人生还早,谁能笑到最后呢,坚持吧!
1.迭代器协议
由于生成器自动实现了迭代器协议,我们有必要了解迭代器协议是什么,才能更好的理解生成器。
1)迭代器协议:对象要提供__next()__方法,它要么返回迭代中的下一个对象,要么引起一个StopIteration错误,终止迭代
2)可迭代对象:实现了迭代器协议的对象
3)协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)使用迭代器协议访问对象。
for循环的本质:循环所有对象,全都是使用迭代器协议
(字符串,列表,元组,字典,集合,文件对象)这些都不是可迭代对象,只不过在for循环式,调用了他们内部的__iter__方法,把他们变成了可迭代对象
list = [‘a‘,‘b‘,1,2] # for i in list: # print(i) list_iter = list.__iter__()#调用__iter__方法将list对象变成可迭代对象 print(list_iter.__next__())依次调用,知道引起StopIteration错误 print(list_iter.__next__()) print(list_iter.__next__()) print(list_iter.__next__())
用while循环模拟for循环做的事情
list_iter = list.__iter__()
while True:
try:
print(list_iter.__next__())
except StopIteration:
print(‘迭代完毕,可以终止‘)
break
迭代器对象的本质是一种数据流,它只是一个有序的序列,我们不能提前知道它的长度,只有不断通过__next__()取出下一个值。
Interator
甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
优点
1):迭代器提供了一种不依赖于索引的取值方式,这样就可以遍历那些没有索引的可迭代对象了(字典,集合,文件)
2):迭代器与列表比较,迭代器是惰性计算的,,只有在需要返回下一个数据时才计算,更节省内存
缺点:
1):无法获取迭代器的长度,使用不如列表索引取值灵活
2):一次性的,只能往后取值,不能倒着取值
如何查看一个对象是不是可迭代对象和迭代器对象
from collections import Iterable,Iterator#导入模块 list = [‘a‘,‘b‘,1,2] list_iter = list.__iter__() #isinstance print(isinstance(list,Iterable))#是否是可迭代对象 print(isinstance(list,Iterator))#是否是迭代器对象 print(isinstance(list_iter,Iterable)) print(isinstance(list_iter,Iterator))
小结:
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列,也就是说你需要取值时才给你取;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
协程函数
如果在一个函数内部yield的使用方式是表达式形式的话,如x=yield,那么该函数称为协程函数,比线程更小
def eater(name): food_list=[] while True: food=yield food_list food_list.append(food)#因为有yied e=eater(‘铁根‘) #一个生成器的内存地址 print(next(e)) #初始化迭代器 print(e.send(‘包子‘)) print(e.send(‘韭菜馅包子‘)) print(e.send(‘大蒜包子‘))
2.生成器
通过列表生成式,我们可以创建一个列表。但是我们知道受内存的限制,我们的列表容量是有限的,而且创建包含100万个元素的列表,我们只用到前几个,剩下的都是浪费内存空间。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
l=[x*x for x in range(10)] print(l) g=(x*x for x in range(10)) print(g) 打印结果 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] <generator object <genexpr> at 0x0000000001E70F10>
取generator值用__next__()一个一个打印出来
print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) print(g.__next__()) 0 1 4 9 16 25
generator也是可迭代对象,所以也可以使用for循环
for i in g: print(i) 0 1 4 9 16 25 36 49 64 81
所以,我们创建了一个generator后,基本上永远不会调用next()
,而是通过for
循环来迭代它,并且不需要关心StopIteration
的错误。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return ‘done‘
fib(20)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
仔细观察,可以看出,fib
函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib
函数变成generator,只需要把print(b)
改为yield b
就可以了:
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return ‘done‘ f = fib(6) print(f) <generator object fib at 0x0000000002170F10>
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return
语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()
的时候执行,遇到yield
语句返回,再次执行时从上次返回的yield
语句处继续执行。
定义generator的另一种方法。如果一个函数定义中包含yield
关键字,那么这个函数就不再是一个普通函数,而是一个generator
我们把函数变成generator后,基本上也不再使用__next__()方法,都是用for循环来迭代,但是用for
循环调用generator时,发现拿不到generator的return
语句的返回值。
def fib(max): n, a, b = 0, 0, 1 while n < max: # print(b) yield b a, b = b, a + b n = n + 1 return ‘done‘ for i in fib(5): print(i) 1 1 2 3 5
如果想要拿到返回值,必须捕获StopIteration
错误,返回值包含在StopIteration
的value
中:
while True: try: x=next(g) print(x) except StopIteration as e: print(‘Generator return value:‘,e.value) break 2 3 5 Generator return value: done
看到一张图方便理解列表等容器,生成器,可迭代对象,迭代器之间的关系
小结:
generator可以是表达式也可以是函数,它保存的是算法,同时它是iterable对象,它也是一个generator。
python迭代器和生成器