Python函数(十一)-生成器

首先看一下什么是列表生成式

>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> a=[]
>>> for i in range(10):
...     a.append(i*2)
...
>>> a
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

这一句代码就实现了三句代码的效果,这一句代码就是列表生成式

列表如果存的数据太多,就会占用很大的存储空间

如果只取列表中的一些数据,那么其它不用的数据占用的存储空间就白占了

生成器也能存储数据,但是它只记录当前数据,剩下的数据都还没生成,这样就不会占用太多的存储空间

怎么创建一个生成器呢?

>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> (i*2 for i in range(10))
<generator object <genexpr> at 0x0000021C9C2E5258>

这样就是一个生成器了,没有直接生成数据

要取一个数据就生成一个数据

那么怎么获取生成器里的数据呢?

>>> b = (i*2 for i in range(10))
>>> b
<generator object <genexpr> at 0x0000021C9C2E5308>
>>> b.__next__()
0
>>> b.__next__()
2
>>> b.__next__()
4
>>> next(b)
6
>>> next(b)
8
>>> next(b)
10

生成器使用next()方法获取数据,next(b),这是Python3和Python2通用的方法

Python3中还可以用__next__()方法,b.__next__()

Python2中用next()方法,b.next()

但是用next()方法一次次取数据太麻烦,所以通常都用for循环来打印数据

>>> c = (i*2 for i in range(10))
>>> for n in c:
...     print(n)
...
0
2
4
6
8
10
12
14
16
18

如果函数里有yield关键字,这个函数就是生成器

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

def test(n):
    m = 0
    b = 0
    while m<n:
        print("before yield")
        yield b
        b = b+3
        print("after yield")
        m =m+1
    return "test return"

a =test(10)

while True:
    try:
        b = a.__next__()
        print("in the next",b)
    except StopIteration as e:
        print(e.value) #StopIteration的value为生成器的返回值
        exit()

运行结果

运行过程:

首先是调用test()函数

然后执行while循环

到__next__()方法的时候,跳到test()函数

执行完yield后,没继续执行下面的语句,而是返回到__next__()方法后的语句

执行完该语句后继续执行while循环,执行__next__()方法

然后又跳转到yield后的语句

生成器调用next()方法的时候执行,执行到生成器中的yield的时候返回,然后执行next()方法后的语句,再执行到next()方法的时候,就会跳到执行yield的语句,之后执行yield后的语句

用生成器实现单线程多并发

# -*- coding:utf-8 -*-
__author__ = "MuT6 Sch01aR"

import time

def consumer(name):
    print('%s准备吃包子' %name)
    while True:
        baozi = yield
        print('%s包子来了,被%s吃了' %(baozi,name))

def producer():
    c = consumer('张三')
    c2 = consumer('李四')
    c.__next__()
    c2.__next__()
    print('我开始准备做包子了')
    for i in range(10):
        time.sleep(1)
        print('我做了2个包子')
        c.send('肉') #调用yield,并传值
        c2.send('菜')

if __name__ == '__main__':
    producer()

send方法不仅可以调用yield,还给yield传值

运行结果

实现了单线程多并发的效果

posted @ 2018-02-03 20:06  Sch01aR#  阅读(192)  评论(0编辑  收藏  举报