zoukankan      html  css  js  c++  java
  • Python--生成器

    学习生成器之前,首先需要认识列表生成式,直奔主题。

    1、简单列表生成式示例:

    1 b = [ i for i in range(10)]
    2 print(b)
    3 
    4 >>>
    5 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    看样子好像很NB的样子,其实它等价于:

    1 c = []
    2 for i in range(10):
    3     c.append(i)
    4 print(c)
    5 
    6 >>>
    7 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

    其实还是有点NB的,毕竟代码少了,手动嘻嘻嘻!

    2、削微高级点的列表生成式:

    1 def func(x):
    2     a = x + 1
    3     b = a + x
    4     return b
    5 d = [ func(i) for i in range(10) ]
    6 print(d)
    7 
    8 >>>
    9 [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]

    生成式生成的数据可以交给函数处理,进而得到预定规则的一组数据。

    下面有请主角登场!!!!

    生成器:在Python中,一边循环一边计算的机制,称为生成器:generator。

      我们知道了,通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。

    创建生成器的姿势:将生成式的"[]"换成"()"就ok了,是不是超级简单。。。

     1 a = ( i for i in range(10))
     2 print(a)
     3 for i in a:
     4     print(i)
     5 
     6 >>>
     7 <generator object <genexpr> at 0x00000270A14EB0B0>
     8 0
     9 1
    10 ..
    11 9

    由上面的例子可见,打印的a已不是一个列表,而是a的内存地址。而且a可以通过for循环将其中的值取出。

    就用一个小栗子完成生成式和生成器比较吧:

    1 # 生成b需要很长时间
    2 b = [ i for i in range(100000000) ]
    3 # 生成c很快,因为不需要实际写数据,c的数据是在使用时才生成
    4 c = ( i for i in range(100) )

    生成器特性:

    1.生成器只能一个个的取数据
    2.生成器只有在调用时才会生成相应的数据
    3.生成器只记住当前位置的地址,之前的的内存地址都没了
    4.只有一个__next__()方法
    5.生成器不能根据索引位置取值
    1 c = ( i for i in range(100) )
    2 print(c.__next__())
    3 print(c.__next__())
    4 print(c[0])
    5 
    6 >>>
    7 0
    8 1
    9 TypeError: 'generator' object is not subscriptable

    #############################################################

    示例:了解斐波那契数列(下个数为前两个数的和)

     1 def fib(max):
     2     n, a, b = 0, 0, 1
     3     while n < max:
     4         print(b)
     5         a, b = b, a+b  #注意a, b = b, a+b 等价于 t(b,a+b);a=t[0];b=t[1],而不是 a=b;b=a+b
     6         n = n + 1
     7     return "done"
     8 fib(7)
     9 >>>
    10 1
    11 1
    12 2
    13 3
    14 5
    15 8
    16 13

    使斐波那契数列变成一个生成器

     1 def fib(max):
     2     n, a, b = 0, 0, 1
     3     while n < max:
     4         yield b  #yield返回当前状态的值,程序停在此处
     5         a, b = b, a+b
     6         n = n + 1
     7     return "---done---" 
     8 # fib(5)  #此时执行,并无返回值,因为没有取值。使用__next__()进行取值
     9 f = fib(5)
    10 print(f.__next__())
    11 print(f.__next__())
    12 print(f.__next__())
    13 print(f.__next__())
    14 print(f.__next__())
    15 print(f.__next__())
    16 
    17 >>>
    18 1
    19 1
    20 2
    21 3
    22 5
    23 StopIteration: ---done---  # 当超出时报错
    使用yield后,可以使用__next__()方法,中断函数的执行,在中断之后可以执行其他的操作,然后还可以通过__next__()再进入
    例如:
     1 def fib(max):
     2     n, a, b = 0, 0, 1
     3     while n < max:
     4         # print(b)
     5         yield b  #yield返回当前状态的值,程序停在此处
     6         a, b = b, a+b
     7         n = n + 1
     8     return "---done---"  
     9 f = fib(5)
    10 f.__next__()
    11 X = f.__next__()
    12 print(X)
    13 print("休息一会儿,马上就回来了")
    14 Y = f.__next__()
    15 print(Y)
    16 print("又走了...")
    17 Z = f.__next__()
    18 print(Z)
    19 >>>
    20 1
    21 休息一会儿,马上就回来了
    22 2
    23 又走了...
    24 3

    能看到这,那你又又又又又又要学到了:抓异常、抓异常、抓异常。重要的事情说三遍!!!

     1 def fib(max):
     2     n, a, b = 0, 0, 1
     3     while n < max:
     4         # print(b)
     5         yield b  #yield返回当前状态的值,程序停在此处
     6         a, b = b, a+b
     7         n = n + 1
     8     return "---done---"
     9 g = fib(8)
    10 while True:
    11     try:
    12         x = next(g)  # 等价于 x = g.__next__()
    13         print("value:", x)
    14     except StopIteration as e: #当出现StopIteration时执行下面的代码
    15         print("Generator return value", e.value)
    16         break
    17 
    18 >>>
    19 value: 1
    20 value: 1
    21 value: 2
    22 value: 3
    23 value: 5
    24 value: 8
    25 value: 13
    26 value: 21
    27 Generator return value ---done---

    生成器示例高级,实现并行:

    import  time
    def consum(name):
        print("%s 要来吃包子了" % (name))
        while True:
            baozi = yield
            print("%s个包子被%s吃了" % (baozi, name))
    
    def product(name):
        d = consum("flb")
        d2 = consum("wxl")
        d.__next__() # next唤醒yield,不会给yield传值
        d2.__next__()
        print("%s要来做包子了" %(name))
        for i in  range(3):
            time.sleep(1)
            print("%s做了%s个包子" %(name,i))
            d.send(i)  # send唤醒yield,会给yield传值
            d2.send(i)
    product("TJ")
    
    >>>
    flb 要来吃包子了
    wxl 要来吃包子了
    TJ要来做包子了
    TJ做了0个包子
    0个包子被flb吃了
    0个包子被wxl吃了
    TJ做了1个包子
    1个包子被flb吃了
    1个包子被wxl吃了
    TJ做了2个包子
    2个包子被flb吃了
    2个包子被wxl吃了

    END!!!

  • 相关阅读:
    X Window研究笔记(5)
    R语言中 %in%操作符
    R语言中的for循环结构
    R语言中将数据框中的连续型变量转变为类别型变量
    R语言中fig函数,图形布局的精细控制
    R语言中向量取唯一值
    R语言中计算最大值、最小值、平均数、中位数、方差、标准差、协方差、相关系数
    R语言中的数组
    R语言中同时对数据框的多列进行排序
    R语言中求数据框的每一列值的最大值、最小值、平均数、中位数、方差、标准差
  • 原文地址:https://www.cnblogs.com/sunnytomorrow/p/13081734.html
Copyright © 2011-2022 走看看