zoukankan      html  css  js  c++  java
  • 迭代器和生成器

    迭代器和生成器;
     >>> 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
  • 相关阅读:
    .net类库里ListView的一个BUG
    获取lable的caption, 摘抄还未测试可用否
    (转) lua实现split的简易方法
    2. SharePoint Online 开发,请联系qq512800530。加好备注。(不要发站内信。。。)
    1. android
    开发人员应关注的20个jQuery网站/博客
    Temp
    彩票项目开发节项
    求android ble 解决方案!
    自己开发的工作流引擎
  • 原文地址:https://www.cnblogs.com/brace2011/p/9194071.html
Copyright © 2011-2022 走看看