迭代器和生成器

Posted brace2011

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器和生成器相关的知识,希望对你有一定的参考价值。

迭代器和生成器;
 >>> a = [1,2,3,4]
 >>> a
 [1, 2, 3, 4]
 
 列表生成式:
 >>> [i*2 for i in range(10)]
 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
 
 生成器:
 通过列表生成式就可以直接创建一个列表,但是受内存的限制,列表容量肯定是有限的,
 常规的列表的有些元素用不上却占用了不少空间。
 
 在python中,一边循环一边计算的机制,叫生成器:generator
 
 创建生成器的方式:
 
 1. 将生成式的[]改为(),就成为了生成器;
  >>> (i*2 for i in range(10))
  <generator object <genexpr> at 0x03811EA0>
  
  
  >>> for n in (i*2 for i in range(10)):
  ...   print(n)
  ...
  0
  2
  4
  6
  8
  10
  12
  14
  16
  18
 
  >>> a = [ i*2 for i in range(10000000) ]    #耗时长;
  >>> b = ( i*2 for i in range(10000000) )    #很快,只是生成一个算法;
  >>>
  >>> a[1000]
  2000             #元素是已经生成好的
  >>> b[1000]            #元素还没生成,所以出错;
  Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  TypeError: ‘generator‘ object is not subscriptable
  >>>
 
  生成器只有在调用时才会生成相应的数据;
  
  生成器的元素只能一个一个的来取。可以用next来取,
  
  只记住当前的位置;
  只有一个__next__方法,Python2.7为next()
  
  >>> b.__next__()
  0
  >>> b.__next__()
  2
  >>> b.__next__()
  4
  >>> b.__next__()
  6
  >>>
  
  生成器非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现,可以用函数来实现;
  
  斐波拉契列:
  1,1,2,3,5,8,13,21,34,.........
  
  def fib(max):
   n, a, b = 0, 0, 1
   while n < max:
    print(b)
    a, b = b, a+b
    n += 1
   return "done"
  
  fib(10)
  
  输出:
  1
  1
  2
  3
  5
  8
  13
  21
  34
  55
   
 
  def fib(max):
   n, a, b = 0, 0, 1
   while n < max:
    yield b     #改为yield后就成了生成器
    a, b = b, a+b
    n += 1
   return "done"
  
  print(fib(10))
  for n in fib(10):
   print(n)
   
   
  输出:
  <generator object fib at 0x02C1F150>
  1
  1
  2
  3
  5
  8
  13
  21
  34
  55
  
  
 def fib(max):
  n, a, b = 0, 0, 1
  while n < max:
   yield b
   a, b = b, a+b
   n += 1
  return "done"
 
 f = fib(10)
 f.__next__()
 f.__next__()
 print("========")
 f.__next__()
 print("========")
 print(f.__next__())
 print(f.__next__())
 print("+++++++++")
 for n in f:
  print(f.__next__())
 
 输出: 
 ========
 ========
 3
 5
 +++++++++
 13
 34
 Traceback (most recent call last):
 File "D:/Python3/python_project/Project_1/Day-06-17/genrator.py", line 33, in <module>
  print(f.__next__())
 StopIteration: done
 
 Process finished with exit code 1
 
 
 # 捕捉异常:
 def fib(max):
  n, a, b = 0, 0, 1
  while n < max:
   yield b
   a, b = b, a+b
   n += 1
  return "done"
 
 f = fib(10)     #仅仅是生成生成器
 f.__next__()    #初始化并生成一个数据
 f.__next__()
 print("========")
 f.__next__()    #产生第三数据
 print("========")
 print(f.__next__())   
 print(f.__next__())   #产生第五数据,退出不妨碍往后产生数据
 print("+++++++++")
 try:
  for n in f:
   print(f.__next__()) #产生第六数据
 except StopIteration :  #取完后就会溢出,异常被捕获而中断;
  print("done!")
 
 输出:
 ========
 ========
 3
 5
 +++++++++
 13
 34
 done!
 

#########################################################
案例:通过yield实现在单线程的的情况下实现并发预算效果,即所谓的多线程效果,也称为协程
 
 import time
 def consumer(name):
  print("%s 准备吃包子了!"% name)
  while True:
   baozi = yield
   print("包子[%s]来了,一半被[%s]吃了"% (baozi, name))
 
 def producer(name):
  c1 = consumer("A")     #只是把函数变成了生成器,其他什么也没做
  c2 = consumer("B")
  c1.__next__()      #初始化准备吃包子,此时生成器开始执行,走到yield开始卡住了(等待生成包子),因为此时生成器还没生成数据。
  c2.__next__()
  print("%s开始准备做包子了!"% name)
  for i in range(5):
   time.sleep(1)
   print("%s 做了2个包子"% name)
   c1.send("韭菜")        #给生成器生成一个数据,
   c2.send("奶黄")
 
 producer("Lucy") 
 
输出:
 A 准备吃包子了!
 B 准备吃包子了!
 Lucy开始准备做包子了!
 Lucy做了2个包子
 包子[韭菜]来了,被[A]吃了
 包子[奶黄]来了,被[B]吃了
 Lucy做了2个包子
 包子[韭菜]来了,被[A]吃了
 包子[奶黄]来了,被[B]吃了
 Lucy做了2个包子
 包子[韭菜]来了,被[A]吃了
 包子[奶黄]来了,被[B]吃了
 Lucy做了2个包子
 包子[韭菜]来了,被[A]吃了
 包子[奶黄]来了,被[B]吃了
 Lucy做了2个包子
 包子[韭菜]来了,被[A]吃了
 包子[奶黄]来了,被[B]吃了 
 
 
 
 
迭代器:
 可以直接作用于for循环的数据类型有以下几种:
 一类:集合数据类型,如:list,tuple,dict,set,str等
 一类:generator 包括生成器和带yield的generation function
 
 这些可以直接作用于for循环的对象统称为可迭代对象,Iterable
 
 可以使用isinstance()判断一个对象是否是Iterable
 
 
 >>> from collections import Iterable
 >>> isinstance("abc",Iterable)
 True
 >>> isinstance([1,2,3,4],Iterable)
 True
 >>> isinstance({},Iterable)
 True
 >>> isinstance(10,Iterable)
 False
 >>>
 
 而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下个值,直到最后抛出异常
 
 可以被next()函数调用并不断返回下一个值的对象统称为迭代器:Iterator
 
 
 >>> from collections import Iterator
 >>> isinstance([1,2,3,4],Iterator)
 False
 >>>
 >>> isinstance((x *2 for x in range(10)),Iterator)
 True
 >>>
 
 生成器都是Iterator 对象,但list,dict,str等虽然是Iterable,却不是Iterator
 
 把list,dict,str等Iterable变成Iterator迭代器,可以使用iter()函数;
 
 >>> isinstance(iter([1,2,3,4]),Iterator)
 True
 >>> x = iter([1,2,3,4])
 >>> x.__next__()
 1
 >>> x.__next__()
 2
 >>> x.__next__()
 3
 >>> x.__next__()
 4
 
 Python的Itertor对象表示的是一个数据流,可以被next()函数调用并不停的返回下一个数据,直到没有数据时抛出StopIteration异常
 可以把这个数据流看着是一个有序序列,但我们却不知道序列的长度,只能不断通过next()函数实现按需计算下一个数据。
 所以Iteratorhi的计算是惰性的,只有在需要返回下一个数据时才会计算。
 
 Iterator甚至可以表示一个无限大的数据流,例如全体自然数,但使用list是永远不可能存储全体自然数的(五穷尽的数据)。
 
 
 it = iter([1,2,3,4,5,6,6,6])
 while True:
  try:
   x = next(it)
   print(x)
  except StopIteration:
   break
 
 输出:
 1
 2
 3
 4
 5
 6
 6
 6




















































































































































































































































































































以上是关于迭代器和生成器的主要内容,如果未能解决你的问题,请参考以下文章

5.迭代器和生成器

迭代器和生成器

Python迭代器和生成器

Python/迭代器和生成器

迭代器和生成器

python的迭代器和生成器