生成器 yield 协程(python)

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. 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
posted @ 2018-06-22 14:11  rianley  阅读(154)  评论(0编辑  收藏  举报