迭代器
可迭代对象
有iter()方法的就是可迭代对象,列如列表,字典,元祖,集合,文件对象等都是
d = {'key1':1,'key2':2,'key3':3}res = d.__iter()__print(res)>> <dict_keyiterator object at 0x000321312042143132W>res.__next__()res.__next__()res.__next__()res.__next__()>>>key1key2key3报错StopIterationwhile True:try:res.__next()__except StopIteration as e:break>>> key1,key2,key3
迭代器对象
内置有next()方法并且还内置有iter()方法的对象
调用next()方法,就会得到迭代器的下一个值
调用iter()方法,就会得到迭代器本身,那为啥还需要iter()方法呢,就是为了要和可迭代对象的for方法保持一致
for 方法的执行步骤:
- 调用对象的iter()方法,得到它的一个迭代器对象
- 调用该迭代器的next()方法,拿到一个返回值,赋值给key
循环执行第二步直到抛出StopIteration异常,for循环捕捉到异常并结束循环
x = ['dasd','java','python']y = iter(x)print(next(y))print(next(y))print(next(y))
一旦迭代器用完了(也就是说,完全迭代了),就没有什么可以迭代的了,所以第二次迭代不会产生任何结果
a = map(int,['1','2','3'])for i in a:print(i,end=',')for i in a:print(i,end=',')>>>>1,2,3
生成器(自定义的迭代器)
定义
列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
生成可迭代的对象 : 节省空间和时间创建
把[]改成()
使用yield关键字
def gen(n):for i in range(n):yield i*i#return i*i 如果是return,当n=0是直接就返回了x = gen(5)for i in x:print(x,end=' ')
工作原理
生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常,
可用next()调用生成器对象来取值。next 两种方式 t.next() | next(t)。可用for 循环获取返回值(每执行一次,取生成器里面一个值)
- yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
- .send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果,换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10
def test():i = 0while i < 5:temp = yield iprint('temp is %s'%temp)i += 1a = test() #a是一个生成器a.__next__() #-->a.send(None),相当于发送一个None给生成器,此时i = 0,停留在yielda.__next__()a.__next__()a.send('hello')a.__next__()a.__next__() #i > 5了,此时生成器取完了,打印StopIteration错误>>>>>0 返回i= 0,不打印后面的printtemp is None 返回i=11temp is None 返回i=22temp is hello 返回i=33temp is None 返回i=44Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration#第一次取值:yield 返回了 i 值 0,停在yield i,temp没赋到值。第二次取值,开始在print,temp没被赋值,故打印None,i加1,继续while判断,yield 返回了 i 值 1,停在yield i
生成斐波拉契数列:
def fib(max):n,a,b = 0,0,1while n < max:yield ba,b = b,a+b #a,b = b ,a+b其实相当于t =a+b ,a =b ,b =tn += 1return 'done'for i in fib(6):print(i,end=' ')>>>>1 1 2 3 5 8#可以看出这个打印并不返回return的'done',如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的valueg = fib(7)while True:try:x = g.__next__()print(x,end=' ')except Exception as e:print(e.value)break>>>1 1 2 3 5 8 13 done
yield单线程并发
二维列表转化为一维列表import timedef consumer(name):print(f'{name} 准备学习啦!')while True:lesson = yieldprint(f'开始[{lesson}],[{name}]老师来讲课了')def producer():c1 = consumer('A')c2 = consumer('B')c1.__next__()c2.__next__()print('开始上课了')for i in range(10):time.sleep(1)print('到了2个同学')c1.send(i)c2.send(i)if __name__ == '__main__':producer()
如果是多维列表转化a = [[1,2,3],[4,3,2],[1,2,34,5,6]]num_list = []def handlelist():for num in a:for i in num:yield i*iprint(list(handlelist))>>[1, 4, 9, 16, 9, 4, 1, 4, 1156, 25, 36]
a = [1,2,3,[1,2,3,[1,2,[232,1,1,2]]],[[3,3,2],4,3,2],[1,2,34,5,6]]def enumlist(a):try:for num in a:for i in enumlist(num):yield iexcept:yield aprint(list(enumlist(a)))>>[1, 2, 3, 1, 2, 3, 1, 2, 232, 1, 1, 2, 3, 3, 2, 4, 3, 2, 1, 2, 34, 5, 6]
