• 6 生成器 yield 协程


    1.生成器

    ----> 1 b = [x*2 for x in range(100000000000)]
    
    MemoryError: 

    想生成一个存放很多数据的列表,但是又不想内存占用太多

    每次用一个生成一个,最好

      2)列表生成器:生成多个值,每次生成1个

    In [29]: c = (x*2 for x in range(10))
    
    In [30]: c
    Out[30]: <generator object <genexpr> at 0x7f8b5c0c6960>
    
    
    In [31]: next(c)
    Out[31]: 0
    
    In [32]: next(c)
    Out[32]: 2
    
    In [40]: next(c)
    Out[40]: 18
    
    In [41]: next(c)                   #迭代器没有数据就出现异常了
    ---------------------------------------------------------------------------
    StopIteration                             Traceback (most recent call last)
    <ipython-input-41-73b012f9653f> in <module>()
    ----> 1 next(c)

    2.斐波那契数列

      1)版本1:a,b = b,a+b

    def creat_num():
        a,b = 0,1
    
        for i in range(5):
            print(b)
            a,b = b,a+b
    
    creat_num()
    
    
    1
    1
    2
    3
    5

      2)版本2:生成器 yield b

     def creat_num():
         a,b = 0,1
         
         for i in range(5):
             yield b
             a,b = b,a+b
         
     creat_num()

      3)版本3:当成模块导入

      可以通过 next() 函数获得生成器的下一个返回值:

    def creat_num():
        print("--start---")
        a,b = 0,1
    
        for i in range(5):
            print("--1--")
            yield b               #每次next执行到yield这里停止
            print("--2---")
            a,b = b,a+b
            print("--3--")
        print("--end---")
    In [4]: a = creat_num()
    
    In [5]: a
    Out[5]: <generator object creat_num at 0x7facd60b5a98>
    
    In [6]: next(a)
    --start---
    --1--
    Out[6]: 1
    
    In [7]: next(a)
    --2---
    --3--
    --1--
    Out[7]: 1
    
    In [8]: next(a)
    --2---
    --3--
    --1--
    Out[8]: 2

      4)版本4:next(a)  和  a.__next__()

    def creat_num():
        print("--start---")
        a,b = 0,1
    
        for i in range(5):
            print("--1--")
            yield b
            print("--2---")
            a,b = b,a+b
            print("--3--")
        print("--end---")
    
    #创建了1个生成器对象
    a = creat_num()
    
    ret = next(a)  #让a这个生成器对象开始执行,如果第一次执行,就从create_num开始部分执行
                  #如果是之前已经执行过了,就从上一次停止的位置开始执行
    ret = next(a) 
    ret = next(a) 

      

    def creat_num():
        print("--start---")
        a,b = 0,1
    
        for i in range(5):
            print("--1--")
            yield b
            print("--2---")
            a,b = b,a+b
            print("--3--")
        print("--end---")
    
    #创建了1个生成器对象
    a = creat_num()
    
    ret = a.__next__()
    print(ret)
    
    #注意:
    #next(a)
    #a.__next__()
    #以上两种方式是一样的

      5)版本5:循环取出生成器的值

    def creat_num():
        print("--start---")
        a,b = 0,1
    
        for i in range(5):
            print("--1--")
            yield b
            print("--2---")
            a,b = b,a+b
            print("--3--")
        print("--end---")
    
    #创建了1个生成器对象
    a = creat_num()
    
    for i in a:                   #循环取出值
        print(i)
    --start---
    --1--
    1
    --2---
    --3--
    --1--
    1
    --2---
    --3--
    --1--
    2
    --2---
    --3--
    --1--
    3
    --2---
    --3--
    --1--
    5
    --2---
    --3--
    --end---

    3。send(‘haha’)

    例子:执行到yield时,gen函数作用暂时保存,返回i的值;temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)

    In [10]: def test():
       ....:     i = 0
       ....:     while i < 5:
       ....:         temp = yield i 
       ....:         print(temp)
       ....:         print(i)
       ....:         i += 1
    In [20]: t =test()
    
    In [21]: t.__next__()
    Out[21]: 0                        #yield i 的返回值  相当于return i 
    
    In [22]: t.__next__()
    --1 None
    --2 0
    Out[22]: 1
    
    In [23]: t.__next__()
    --1 None
    --2 1
    Out[23]: 2
    
    In [24]: t.__next__()
    --1 None
    --2 2
    Out[24]: 3
    
    In [25]: t.send('haha')   #相当于yield i = haha  ,temp =haha
    --1 haha
    --2 3
    Out[25]: 4            #到yield 停止  yield i  返回return i

       2)第一次send(None)

    In [26]: t = test()
    
    In [27]: t.send('lala')
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-27-e48ba033e48c> in <module>()
    ----> 1 t.send('lala')
    
    TypeError: can't send non-None value to a just-started generator
      #直接send 出现异常
    In [29]: t.send(None)    #第一次相当于t.__next__()
    Out[29]: 0
    
    In [30]: t.send('--lala')
    --1 --lala
    --2 0
    Out[30]: 1

     4.yield 多任务  协程

    def test1():
        while True:
            print('===1')
            yield None
    
    def test2():
        while True:
            print('---2')
            yield None
    
    t1 =test1()
    t2 = test2()
    while True :
        t1.__next__()
        t2.__next__()
    ### 运行结果
    ===1
    ---2
    ===1
    ---2
    ===1
    ---2
    ===1
    ---2
    ===1
    ---2
    ===1
    ---2

    5.总结

    生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。

    生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。

    生成器的特点:

    1. 节约内存
    2. 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
  • 相关阅读:
    HDU4289 Control 最大流
    POJ3281 Dining 最大流
    HDU4738 Caocao's Bridges 无向图的桥
    HDU4865 Prince and Princess 强连通分量+二分图判定
    POJ 1904 King's Quest 强连通分量+二分图增广判定
    HDU 4635 Strongly connected 强连通分量
    HDU 4280Island Transport(Dinc非STL 模板)
    POJ 2752Seek the Name, Seek the Fame(next数组妙用 + 既是前缀也是后缀)
    Codeforces Round #346 (Div. 2)E
    POJ2318TOYS(叉积判断点与直线位置)
  • 原文地址:https://www.cnblogs.com/venicid/p/7927849.html
Copyright © 2020-2023  润新知