迭代器
一 迭代
#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单纯地重复,因而不是迭代 print('===>') li=[1,2,3] count=0 while count < len(li): #迭代 print(li[count]) count+=1
二 迭代器
1,迭代器
对于 字符串,列表,元组,我们可使用索引的方式迭代取出其包含的元素。但对于 字典,集合,文件等类型是没有索引的,
若还想取出其 内部包含的元素,则需要一种 不依赖索引的迭代方式,这就是 迭代器
2.可迭代对象
可迭代对象:内置有 __iter__ 方法的对象。即obj.__iter__ 如下: 'hello'.__iter__ (1,2,3).__iter__ [1,2,3].__iter__
3.迭代器
迭代器对象:即内置有 __iter__又内置有__next__方法的对象。 文件类型是迭代器对象 open('a.txt').__iter__() open('a.txt').__next__()
4.注意
迭代器对象一定是可迭代对象,而可迭代对象不一定是迭代器对象
三 迭代器的使用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
dic={'a':1,'b':2,'c':3} iter_dic=dic.__iter__() #得到迭代器对象,迭代器对象即有__iter__又有__next__,但是:迭代器.__iter__()得到的仍然是迭代器本身 iter_dic.__iter__() is iter_dic #True print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) print(iter_dic.__next__()) #等同于next(iter_dic) # print(iter_dic.__next__()) #抛出异常StopIteration,或者说结束标志 #有了迭代器,我们就可以不依赖索引迭代取值了 iter_dic=dic.__iter__() while 1: try: k=next(iter_dic) print(dic[k]) except StopIteration: break #这么写太丑陋了,需要我们自己捕捉异常,控制next,python这么牛逼,能不能帮我解决呢?能,请看for循环
四 for循环
#基于for循环,我们可以完全不再依赖索引去取值了 dic={'a':1,'b':2,'c':3} for k in dic: print(dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
五 迭代器的特点
#优点: - 提供一种统一的,不依赖于索引的迭代方式 - 惰性计算,节省内存 #缺点: - 无法获取长度(只有在next完毕才知道到底有几个值) - 只能往后走,不能往前退
生成器
一 迭代器
函数内部包含yield 被称为生成器(generator),并且不会执行函数内部代码。
def func(): print('====>first') yield 1 print('====>second') yield 2 print('====>third') yield 3 print('====>end') g=func() print(g) #<generator object func at 0x00846BD0> # 生成器就是迭代器 print(g.__iter__) print(g.__next__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #验证 生成器也是一个迭代器 2 from collections import Iterator 3 4 def test(): 5 print('first') 6 yield 1 #相当于1 7 8 g=test() 9 # print(g) 10 print(isinstance(g,Iterator)) 11 12 13 #输出结果 14 True
二 生成器与 return有何区别?
#return只能一次性返回,而yield能返回多次值,可以挂起/保存函数的运行状态
yield 到底做了事情?
1. yield把函数变成生成器 ---》因此,也是迭代器(生成器也是个迭代器) 2. 用return返回值能返回一次,而yield返回多次 3. 函数在暂停以及继续下一次运行时的状态是由yield保存
例子:
1. yield的 add
def add(n,i): return n+i def test(): for i in range(4): yield i g=test() for n in [1,10]: g=(add(n,i) for i in g) ## n = 1 # #g = (add(n,i) for i in g) #[1, 2, 3, 4] # #n = 10 # #g1 = (add(n,i) for i in (add(n,i) for i in g)) # # #此处的n=10 #10,11.12.13 print(list(g)) #结果 # [20, 21, 22, 23]
2. 有无直接 next()
2.1 有直接
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #有直接 next(e) 2 3 def eater(name): 4 print('{} start to eat food '.format(name)) 5 food_list = [] 6 while True: 7 food = yield food_list 8 print('{} get {},to start eat'.format(name,food)) 9 food_list.append(food) 10 11 e = eater('汤姆') 12 13 next(e) #执行这一步!!!!!! 14 print(e.send('铁观音')) 15 print(e.send('西瓜')) 16 print(e.send('烧饼'))
2.2 无直接
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #无next() 2 3 def init(func): #在此添加 装饰器,以替代 next(e) 4 def wrapper(*args,**kwargs): 5 res = func(*args,**kwargs) 6 next(res) 7 return res 8 return wrapper 9 10 @init # eater = init(eater) 11 def eater(name): 12 print('{} start to eat food '.format(name)) 13 food_list = [] 14 while True: 15 food = yield food_list 16 print('{} get {},to start eat'.format(name,food)) 17 food_list.append(food) 18 19 e = eater('汤姆') 20 21 # next(e) #不在此执行这一步 22 print(e.send('铁观音')) 23 print(e.send('西瓜')) 24 print(e.send('烧饼'))
得到同样的结果:
1 汤姆 start to eat food 2 汤姆 get 铁观音,to start eat 3 ['铁观音'] 4 汤姆 get 西瓜,to start eat 5 ['铁观音', '西瓜'] 6 汤姆 get 烧饼,to start eat 7 ['铁观音', '西瓜', '烧饼']