Python_base20181114_生成器

生成器

什么是生成器?
生成器是一种数据类型,它自动实现了迭代器协议(也就是说不用iter把它变成一个迭代器,它本身就能当作迭代器用,本身就能被next,本身就有__next__()方法)。所以,它在某种程度上可以认为是一个迭代器。不过它的功能要比迭代器更强大。因为它可以用来保存函数的状态。它的特点是生内存且效率高。
如何定义一个生成器?
两种形式可以做到这一点:

  • 生成器函数
  • 生成器表达式

在具体说生成器之前,先来说说三元表达式列表推导式
python这么NB的语言也要像C那样有3元表达式,不然就太Low了。

res = 'bjfu' if name == 'vth' else 'pku'

这个等价于C语言中的

name == 'vth'?'bjfu':'pku'

再来说说列表推导式:
列表推导式能够在不产生额外开销的情况下生成一个列表,比for循环生成列表要好用。

l = [x for x in range(5)]
l = [i for i in range(100) for j in range(20) if i == j]
l1 = [i for i in range(100) if i != 1 for j in range(20) if i == j]
print(l)
print(l1)

列表推导式可以用多个 for if 语句,但是不能出现else语句。
说完了,现在来说一说生成器表达式:
生成器表达式的形式是怎样的?
将列表推导式的[]换成()即可。
max,min,sum,sort,for等都是基于迭代器协议工作的,也就是说,他们可以处理可迭代对象,迭代器,生成器。都没问题。

再来说说生成器函数:
将普通函数中的return语句改成yield语句,这样就把一个普通函数变成了一个生成器函数。这个函数就是一个生成器。

def test():
    yield

print(test())
输出:
<generator object test at 0x00000209A0A91A98>

生成器的优点:
延迟计算(惰性计算),不会像列表推导式那样一次生成一个大列表,这个是next一次就给一个,比较省内存,在处理大规模数据的时候特别有用。
有效提高代码可读性。

生成器特点:
语法和函数类似,只不过是将return换成了yield 。注意returnyield可以在同一个函数中共存,但是写return 并没有什么意义。因为只要函数体中出现了yield ,这个函数就变成了一个生成器,要return 也没用。
自动实现了迭代器协议
只能循环遍历一次(像人的年龄一样,开弓没有回头箭),当一个生成器遍历到抛出StopIteration 异常时,这个生成器就结束了。

生成器之中有一个send()方法,send()方法的工作流程是这样的:
在这里插入图片描述
没时间看图的来看字:
sendnext差不多,只不过send传的参数交给了上一次的yield作为yield表达式的值可以被某变量存储,send还自动启动下一次的yield ,下一次yield表达式中的yield返回值交给send作为send方法的返回值。

下面写一个程序单线程模拟并发效果:

'''
程序思路:
producer靠send生产包子给consumer中的yield返回吃。
'''

from time import sleep
def consumer(name):
    print('start')
    while True:
        baozi = yield # 接收procuder产生的包子 send发送过来的
        sleep(1)
        print('%s开始吃掉包子%s' % (name,baozi))
def producer():
    c1 = consumer('vth')
    c2 = consumer('ygm')
    c1.__next__()
    c2.__next__()
    for i in range(20):
        c1.send(i) # 产生包子给yield
        c2.send(i)

producer()

猜你喜欢

转载自blog.csdn.net/weixin_41687289/article/details/84063397
今日推荐