1.迭代
将某个数据集中的数据‘一个一个挨着取出来’,就是迭代。
1 ''' 2 dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,为了看的更清楚,我们分别把他们转换成集合, 3 然后取差集。 4 ''' 5 #print(dir([1,2].__iter__())) 6 #print(dir([1,2])) 7 print(set(dir([1,2].__iter__()))-set(dir([1,2])))
运行结果:{'__length_hint__', '__setstate__', '__next__'}
其中 __length_hint__表示的是迭代元素的个数。
__next()__表示取出元素
__setstate__设置迭代起始的位置
1 iter_l = [1,2,3,4,5,6].__iter__() 2 # 获取迭代器中元素的长度 3 print(iter_l.__length_hint__()) 4 # 根据索引值指定从哪里开始迭代 5 print('*',iter_l.__setstate__(4)) 6 #一个一个的取值 7 print('**',iter_l.__next__()) 8 print('***',iter_l.__next__()) 9 # 如果再次__next__()会直接报错 10 print('****',iter_l.__next__()) 11 # 报错 停止迭代 StopIteration
使用try except处理这个异常
1 # 使用异常处理机制处理这个机制 2 list_1 = [1,2,3,4,5,6] 3 iterator = list_1.__iter__() 4 while 1: 5 try: 6 item = iterator.__next__() 7 print(item) 8 except StopIteration: 9 break
迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法
对range()进行如下测试:
1 print('__iter__' in dir(range(12))) # True 2 print('__next__' in dir(range(12))) # False 3 from collections import Iterator 4 from collections import Iterable 5 print(isinstance(range(2),Iterator)) # False 不是一个迭代器 迭代器必须同时满足__iter__ __next__ 6 print(isinstance(range(2),Iterable)) # True 是一个迭代对象 __iter__
可迭代协议
可以被迭代的满足的要求就叫做可迭代协议。可迭代协议的定义非常的简单。就是在内部实现了__iter__方法。
分析__iter__方法做了什么事情呢?
1 print([1,2,3].__iter__()) # <list_iterator object at 0x10ae1a2e8> 2 print(range(2).__iter__()) # <range_iterator object at 0x10aeef6f0>
随后就可以快乐的使用for in i xxx 就可以迭代取出内部的数据咯
1 i = range(2).__iter__() # <range_iterator object at 0x10aeef6f0> 2 for j in i: 3 print(j) # 0 i
2.生成器
2.1 生成器函数
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
1 def generator(): 2 print(1) 3 yield 'a' 4 print(2) 5 yield 'b' 6 g = generator() 7 # print(g) # <generator object generator at 0x110419f10> 8 # print(g.__next__()) 9 """ 10 1 11 a 12 """ 13 # print(g.__next__()) 14 """ 15 1 16 a 17 2 18 b 19 """ 20 # print(g.__next__()) # 没有了报错。.StopIteration 21 # 当前 使用for 迭代取出 22 for i in g: 23 print(i) 24 """ 25 1 26 a 27 2 28 b 29 """
生成器有什么好处呢?就是不会一下子在内存中生成太多数据。
假设要生产200w箱娃哈哈. 按需生产。请求一箱。生产一箱。
1 # 200w箱娃哈哈 需要一箱。生产一箱 2 import time 3 def create_wahaha(): 4 for i in range(1,2000000): 5 yield'生产了%s箱娃哈哈'%i 6 7 generator = create_wahaha() 8 # 开始要第一箱娃哈哈 9 for i in range(100): 10 if i == 10: 11 break 12 print(generator.__next__()) 13 time.sleep(1) 14 15 16 print(generator.__next__()) # 生产了11箱娃哈哈 并不会从第一箱开始.除非再次调用create_wahaha() 17 18 19 generator2 = create_wahaha() 20 print(generator2.__next__()) # 生产了1箱娃哈哈
2.2、send
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 def generator(): 2 print(123) 3 content = yield 1 4 print('=====',content) 5 print(456) 6 yield 2 7 g = generator() 8 ret = g.__next__() 9 print("*****",ret) 10 ret = g.send('hello') 11 print('*******',ret) 12 """ 13 123 14 ***** 1 15 ===== hello 16 456 17 ******* 2 18 """ 19 # 使用send获取下一个值的效果和next基本一致 20 # 只是在获取下一个值的时候,给上一个yield的位置传递一个数据 21 # -------- 22 # 第一次使用生成器的时候,必须使用next获取下一个值 23 # 最后一个yield不能接收外部的值
小试牛刀,借助yield计算移动的平均速度
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 def average(): 2 total = 0 3 count = 0 4 avg = None 5 while True: 6 term = yield avg 7 total += term 8 count +=1 9 avg = total / count 10 a = average() 11 # next(a) 12 a.__next__() 13 print(a.send(10)) 14 print(a.send(20)) 15 print(a.send(30))
进一步借助装饰器去掉每一次调用必须执行next()
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 def init(func): #在调用被装饰生成器函数的时候首先用next激活生成器 2 def inner(*agrs,**kwargs): 3 g = func(*agrs,**kwargs) 4 next(g) 5 return g 6 return inner 7 8 @init 9 def average(): 10 total = 0.0 11 count = 0 12 average = None 13 while True: 14 term = yield average 15 total += term 16 count += 1 17 average = total / count 18 g_avg = average() 19 # next(g_avg) 在装饰器中已经执行了该方法 20 print(g_avg.send(10)) 21 print(g_avg.send(20))