迭代器

可迭代对象

iter()方法的就是可迭代对象,列如列表,字典,元祖,集合,文件对象等都是

  1. d = {'key1':1,'key2':2,'key3':3}
  2. res = d.__iter()__
  3. print(res)
  4. >> <dict_keyiterator object at 0x000321312042143132W>
  5. res.__next__()
  6. res.__next__()
  7. res.__next__()
  8. res.__next__()
  9. >>>
  10. key1
  11. key2
  12. key3
  13. 报错StopIteration
  14. while True:
  15. try:
  16. res.__next()__
  17. except StopIteration as e:
  18. break
  19. >>> key1,key2,key3

迭代器对象

内置有next()方法并且还内置有iter()方法的对象
调用next()方法,就会得到迭代器的下一个值
调用iter()方法,就会得到迭代器本身,那为啥还需要iter()方法呢,就是为了要和可迭代对象的for方法保持一致
for 方法的执行步骤:

  1. 调用对象的iter()方法,得到它的一个迭代器对象
  2. 调用该迭代器的next()方法,拿到一个返回值,赋值给key
  3. 循环执行第二步直到抛出StopIteration异常,for循环捕捉到异常并结束循环

    1. x = ['dasd','java','python']
    2. y = iter(x)
    3. print(next(y))
    4. print(next(y))
    5. print(next(y))

    一旦迭代器用完了(也就是说,完全迭代了),就没有什么可以迭代的了,所以第二次迭代不会产生任何结果

    1. a = map(int,['1','2','3'])
    2. for i in a:
    3. print(i,end=',')
    4. for i in a:
    5. print(i,end=',')
    6. >>>>1,2,3

    如果要多次迭代,则需要转化为列表

    生成器(自定义的迭代器)

    定义

    列表所有数据都在内存中,如果有海量数据的话将会非常耗内存。如果列表元素按照某种算法推算出来,那我们就可以在循环的过程中不断推算出后续的元素,这样就不必创建完整的list,从而节省大量的空间。
    生成器是一个特殊的程序,可以被用作控制循环的迭代行为,python中生成器是迭代器的一种,使用yield返回值函数,每次调用yield会暂停,而可以使用next()函数和send()函数恢复生成器。
    生成可迭代的对象 : 节省空间和时间

    创建

  4. 把[]改成()

  5. 使用yield关键字

    1. def gen(n):
    2. for i in range(n):
    3. yield i*i
    4. #return i*i 如果是return,当n=0是直接就返回了
    5. x = gen(5)
    6. for i in x:
    7. print(x,end=' ')

    工作原理

    生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常,

  6. 可用next()调用生成器对象来取值。next 两种方式 t.next() | next(t)。可用for 循环获取返回值(每执行一次,取生成器里面一个值)

  7. yield相当于 return 返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的下一条语句开始执行。
  8. .send() 和next()一样,都能让生成器继续往下走一步(下次遇到yield停),但send()能传一个值,这个值作为yield表达式整体的结果,换句话说,就是send可以强行修改上一个yield表达式值。比如函数中有一个yield赋值,a = yield 5,第一次迭代到这里会返回5,a还没有赋值。第二次迭代时,使用.send(10),那么,就是强行修改yield 5表达式的值为10,本来是5的,那么a=10
    1. def test():
    2. i = 0
    3. while i < 5:
    4. temp = yield i
    5. print('temp is %s'%temp)
    6. i += 1
    7. a = test() #a是一个生成器
    8. a.__next__() #-->a.send(None),相当于发送一个None给生成器,此时i = 0,停留在yield
    9. a.__next__()
    10. a.__next__()
    11. a.send('hello')
    12. a.__next__()
    13. a.__next__() #i > 5了,此时生成器取完了,打印StopIteration错误
    14. >>>>>
    15. 0 返回i= 0,不打印后面的print
    16. temp is None 返回i=1
    17. 1
    18. temp is None 返回i=2
    19. 2
    20. temp is hello 返回i=3
    21. 3
    22. temp is None 返回i=4
    23. 4
    24. Traceback (most recent call last):File "<stdin>", line 1, in <module> StopIteration
    25. #第一次取值:yield 返回了 i 值 0,停在yield i,temp没赋到值。
    26. 第二次取值,开始在printtemp没被赋值,故打印Nonei1,继续while判断,
    27. yield 返回了 i 1,停在yield i

    生成斐波拉契数列:

    1. def fib(max):
    2. n,a,b = 0,0,1
    3. while n < max:
    4. yield b
    5. a,b = b,a+b #a,b = b ,a+b其实相当于t =a+b ,a =b ,b =t
    6. n += 1
    7. return 'done'
    8. for i in fib(6):
    9. print(i,end=' ')
    10. >>>>1 1 2 3 5 8
    11. #可以看出这个打印并不返回return的'done',如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value
    12. g = fib(7)
    13. while True:
    14. try:
    15. x = g.__next__()
    16. print(x,end=' ')
    17. except Exception as e:
    18. print(e.value)
    19. break
    20. >>>1 1 2 3 5 8 13 done

    yield单线程并发

    1. import time
    2. def consumer(name):
    3. print(f'{name} 准备学习啦!')
    4. while True:
    5. lesson = yield
    6. print(f'开始[{lesson}],[{name}]老师来讲课了')
    7. def producer():
    8. c1 = consumer('A')
    9. c2 = consumer('B')
    10. c1.__next__()
    11. c2.__next__()
    12. print('开始上课了')
    13. for i in range(10):
    14. time.sleep(1)
    15. print('到了2个同学')
    16. c1.send(i)
    17. c2.send(i)
    18. if __name__ == '__main__':
    19. producer()
    二维列表转化为一维列表
    1. a = [[1,2,3],[4,3,2],[1,2,34,5,6]]
    2. num_list = []
    3. def handlelist():
    4. for num in a:
    5. for i in num:
    6. yield i*i
    7. print(list(handlelist))
    8. >>[1, 4, 9, 16, 9, 4, 1, 4, 1156, 25, 36]
    如果是多维列表转化
    1. a = [1,2,3,[1,2,3,[1,2,[232,1,1,2]]],[[3,3,2],4,3,2],[1,2,34,5,6]]
    2. def enumlist(a):
    3. try:
    4. for num in a:
    5. for i in enumlist(num):
    6. yield i
    7. except:
    8. yield a
    9. print(list(enumlist(a)))
    10. >>[1, 2, 3, 1, 2, 3, 1, 2, 232, 1, 1, 2, 3, 3, 2, 4, 3, 2, 1, 2, 34, 5, 6]