python 迭代器与生成器
一 迭代器
可迭代对象:Iterable,例如,ist,str,tuple,dict,set,range(100)。
具有__iter__方法的叫做可迭代对象。
迭代器:Iterator,例如,文件句柄。
具有__next__,__iter__方法的叫做迭代器。
迭代器调用__iter__()方法还是自身。
可迭代对象与迭代器的关系:
可迭代对象调用了__iter__()方法变成迭代器。
2 判断是否是可迭代对象,迭代器的方法。
1 可迭代对象有__iter__方法,没有__next__方法
迭代器有__iter__ __next__方法
2 from collections import Iterable/Iteration
isinstance()方法
3 for循环的本质
for循环可以遍历一个可迭代对象,也可以遍历一个迭代器。
当遍历一个可迭代对象时,会自动调用其__iter__()方法,变为一个迭代器。然后调用__next__()方法。遇到StopIteration终止。
4 迭代器取值与索引取值的对照
迭代器的缺点:不能定点取值。
不能往回取值。
迭代器的优点:惰性计算,节省内存。
可以遍历字典,集合取值。这点是索引无法做到的。无序且不知道有哪些key值。
二 生成器 Generator
生成器本质上是迭代器。
生成器是用户写出来的。
1 生成器的分类
带有yield关键字的生成器函数
由生成器表达式生成的生成器
2 生成器函数
带有yield关键字的函数叫做生成器函数。
与普通函数的不同之处:调用生成器函数返回来是生成器。
yield关键字:
与return相同的部分:
与rerurn不同的部分:
三 生成器的应用
生成器可以模仿管道的概念,借助生成器,可以一直往外传值。
也可以用send方法给生成器传值。
def foo(): money=0 day=0 average=0 while True: value=yield average money+=value day+=1 average=money/day g=foo() print(g.__next__()) print(g.send(200))
一些想法:
想用生成器,首先是要定义函数,函数体内有yield关键字。
生成器一般与循环配合的使用。
生成器通过yield向外传值。也可以用send往内传值。
四 egon课上讲的例子。
表达式形式的生成器到底有什么用。 拿到生成器,从外边给yield传值。
注意:返回来看,send方法调用的必是生成器,send括号内的内容给生成器,拿到生成器后面的返回值。send的作用,传值和__next__()
进阶一,yiled没有返回值。
def init(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) res.send(None) #等价于next(res),等价于res.__next__() return res return wrapper @init def eater(name): print('{} ready to eat '.format(name)) while True: food=yield print('{} is eating {}'.format(name,food)) e=eater('alex') e.send('dog shit')
输出:
alex ready to eat alex is eating dog shit
进阶二 yield加上返回值。
def init(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) res.send(None) #等价于next(res),等价于res.__next__() return res return wrapper @init def eater(name): print('{} ready to eat '.format(name)) food_list=[] while True: food=yield food_list food_list.append(food) print('{} is eating {}'.format(name,food)) e=eater('alex') print(e.send('dog shit')) print(e.send('cat shit'))
输出:
alex ready to eat alex is eating dog shit ['dog shit'] alex is eating cat shit ['dog shit', 'cat shit']
进阶三 进阶二中的狗屎,猫屎参数是写死了。可以专门写一个函数,专门make shit。
分步骤一:
def make_shit(n): for i in range(n): 屎是造出来了,但要传值,给人吃呀
分步骤二:
def make_shit(people,n): for i in range(n): people.send('shit{}'.format(i)) 加入一个参数,造完shit后,通过send传值people
分步骤三:
def init(func): def wrapper(*args,**kwargs): res=func(*args,**kwargs) res.send(None) #等价于next(res),等价于res.__next__() return res return wrapper @init def eater(name): print('{} ready to eat '.format(name)) food_list=[] while True: food=yield food_list food_list.append(food) print('{} is eating {}'.format(name,food)) def make_shit(people,n): for i in range(n): people.send('shit{}'.format(i)) e = eater('alex') make_shit(e,5)
输出:
alex ready to eat alex is eating shit0 alex is eating shit1 alex is eating shit2 alex is eating shit3 alex is eating shit4
make_shit 函数造出shit后不断send给people。
实际上两个函数协同工作的效果。一个函数不断造值,不断发送给另一个函数。 外面的函数给内部的生成器传值。
进阶四:
模拟grep 命令。