概述
1.什么是生成器
以下引用廖雪峰的官方网站
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
2.生成器的创建
(1)将列表生成式的【】变成()
#列表生成式,当生成时元素即打印, 会占用内存,
In [2]: [i for i in range(1,10)]
Out[2]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
#生成器类型,并不会打印数据
In [3]: (i for i in range(1,10))
Out[3]: <generator object <genexpr> at 0x12bde10>
- 读取生成器元素的第一个方式——–next()
#当我们把这个生成器赋给一个变量
In [4]: g = (i for i in range(1,10))
#为该变量使用next()函数获得generator的下一个返回值:
In [5]: g.next()
Out[5]: 1
In [6]: g.next()
Out[6]: 2
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
- 读取生成器元素的第二个方式——for循环
#生成器也是可迭代对象,可以使用for循环
In [8]: g = (i for i in range(1,10))
In [9]: for i in g:
print i
...:
1
2
3
4
5
6
7
8
9
(2)定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, …
def fib(max):
n,a,b = 0,0,1
while n < max:
yield b
a,b = b,a+b
n +=1
g = fib(6)
for i in g:
print i
Tips—–python中的两值交换
x=3、y=4
执行:
x, y = y, x
实质上是 先构造右边的元组(y,x),即(4,3),然后将元组的值依次赋给x,y;
回到Fibonacci的例子上,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代。
那么该generator的函数的执行流程是:
每次在遇到for循环(可以理解为每次读取生成器元素的时候)的时候执行函数(也就是fib(max)函数),遇到yield语句返回,再次执行时从上次返回的的yield语句处执行,读者可以将上面的程序单步调试,就能更深刻理解。
3.生成器的应用
(1)实现生产者消费者模型(有无缓冲区)
???什么时生产者消费者模型
生产者和消费者之间用中间类似一个队列一样的东西串起来。这个队列可以想像成一个存放产品的“仓库”,生产者只需要关心这个“仓库”,并不需要关心具体的消费者,对于生产者而言甚至都不知道有这些消费者存在。对于消费者而言他也不需要关心具体的生产者,到底有多少生产者也不是他关心的事情,他只要关心这个“仓库”中还有没有东西。
- 无缓冲区(没有中间商)
#生成器
def consumer(name):
print "[%s]准备买sugar" %(name)
while True:
size = yield
print "客户[%s]买[%s]包装的sugar" %(name,size)
#引用time模块,才可以使用下面的sleep方法
import time
def producer(name,*size):
#调用生成器赋给变量c1
c1 = consumer("user1")
c2 = consumer("user2")
#c1使用next()方法后才可以执行consumer(),遇到yield停止
c1.next()
c2.next()
print "准备制作sugar....."
for i in size:
time.sleep(1) #等待一秒
print "[%s]制作了[%s]包装的sugar提供给消费者" %(name,i)
#从上次停止的yield处继续执行
c1.send(i) #send 方法将值传给 yield 所在位置的变量
c2.send(i)
producer("producer1","大","中","小")
运行效果:
[user1]准备买sugar
[user2]准备买sugar
准备制作sugar.....
[producer1]制作了[大]包装的sugar提供给消费者
客户[user1]买[大]包装的sugar
客户[user2]买[大]包装的sugar
[producer1]制作了[中]包装的sugar提供给消费者
客户[user1]买[中]包装的sugar
客户[user2]买[中]包装的sugar
[producer1]制作了[小]包装的sugar提供给消费者
客户[user1]买[小]包装的sugar
客户[user2]买[小]包装的sugar
- 有缓冲区(有中间商)
#定义一个中间商队列
sugar_agency = []
def consumer(name):
print "[%s]准备买sugar" %(name)
while True:
size = yield
#将user已经买过的size从sugar_agency队列中移除
sugar_agency.remove(size)
print "客户[%s]买[%s]包装的sugar" %(name,size)
def producer(name,*size):
print "准备制作sugar....."
for i in size:
time.sleep(1)
print "[%s]制作了[%s]包装的sugar提供给消费者" %(name,i)
sugar_agency.append(i)
producer("producer1","大","中","小") #顺序执行完producer()
c1 = consumer("user1") #调用生成器赋给变量c1
c1.next() #从上次停止的yield处继续执行
#send 方法将值传给 yield 所在位置的变量
c1.send("大")
c2 = consumer("user2")
c2.next()
c2.send("中")
print "还剩包装:" #显示user购买完后,还剩的size
for i in sugar_agency:
print i
运行效果:
准备制作sugar.....
[producer1]制作了[大]包装的sugar提供给消费者
[producer1]制作了[中]包装的sugar提供给消费者
[producer1]制作了[小]包装的sugar提供给消费者
[user1]准备买sugar
客户[user1]买[大]包装的sugar
[user2]准备买sugar
客户[user2]买[中]包装的sugar
还剩包装:
小
(2)聊天机器人
def chat_robot():
res = ""
while True:
received = yield res
if "你好" in received or "hi" in received:
print "你好呀!!!欢迎来到yueer的世界"
elif "笨" in received or "傻" in received:
print "请文明用语哦!!!我会生气的,哼~~~"
elif "性别" in received or "女" in received:
print "本姑娘还小,没有谈过恋爱!!!傲娇脸"
elif "我的妈呀" in received or "天" in received:
print "不要吃惊,我就是如此聪慧!!!嘟嘟嘟"
else:
res = "宝宝不明白你在说什么???"
chat = chat_robot()
next(chat) #开始执行
while True:
c = raw_input(">>:")
if not c:
continue
elif c.lower() == "q":
print "byebye ,see you next time!!!lalala"
break
else:
#send方法将用户输入传给yield,根据用户输入作出判断,将返回值赋给response
response = chat.send(c)
#打印response
print response
运行效果:
>>:你好呀,小机器人
你好呀!!!欢迎来到yueer的世界
>>:你是男孩还是女孩呀
本姑娘还小,没有谈过恋爱!!!傲娇脸
>>:我的妈呀,自恋
不要吃惊,我就是如此聪慧!!!嘟嘟嘟
>>:聪慧吗,笨猪猪
请文明用语哦!!!我会生气的,哼~~~
>>:好啊,你比较聪明~
宝宝不明白你在说什么???
>>:q
byebye ,see you next time!!!lalala
最后
以上就是贪玩八宝粥为你收集整理的高级特性之生成器的全部内容,希望文章能够帮你解决高级特性之生成器所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复