iterable:可迭代的;iterator:迭代器;
print(dir([ ])) #打印出列表所拥有的所有方法;
可迭代协议:只要含有__iter__方法的都是可迭代的。
迭代器协议:含有__iter__方法和__next__方法的就是迭代器。
对可迭代的对象调用__iter__方法就可以生成一个迭代器,for循环其实就是在使用迭代器。
迭代器的好处:
1、可以在容器类型中一个一个取值,会把所有的值都取到;
2、可以节省内存空间;
生成器
生成器函数:
只要含有yield关键字的函数都是生成器函数,yield功能和return功能类似,但不会结束函数。
调用生成器函数不会得到返回的具体的值,而是得到一个迭代器。
1 import time 2 def generator1(): 3 a=1 4 print('定义了变量a') 5 yield a 6 b=2 7 print('定义了变量b') 8 yield b 9 g1=generator1() 10 print(g1) #打印g1发现g1只是生成器 11 print(g1.__next__()) 12 print('-'*20) #华丽的分割线 13 time.sleep(3) #sleep看清执行过程 14 print(g1.__next__())
send方法
1、取值功能上和next相同
2、只是取下一个数据时,给上一个yield位置传递一个函数
注意事项:
#第一次使用生成器的时候,是用next取值;
#最后一个yield不能接收外部的值
计算移动平均值__预激协程的装饰器
def wrap1(func):#在调用被装饰生成器函数的时候首先用next激活生成器 def inner(*args,**kwargs): g=func(*args,**kwargs) next(g) return g return inner @wrap1 def averager(): count=0 sum1=0.0 aver=None while True: term=yield aver sum1+=term count+=1 aver=sum1/count g=averager() #next(g),在装饰器中调用了next方法 print(g.send(10)) print(g.send(20)) print(g.send(30))
yield from 可迭代对象a
a迭代产生的每个值都直接传递给生成器的调用者
列表推导器和生成器表达式
list1=['egg%s'% i for i in range(10) ] #列表解析式 print(list1) laomuji=('egg%s'% i for i in range(10)) #生成器表达式 for i in laomuji: print(i)
1、将列表推导器的[]换成()就变成了生成器表达式。
2、列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
3、Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:sum(x**2,for x in range(4))