一、什么是生成器

在Python中,由于受到内存的限制,列表容量肯定是有限的。例如我们创建一个包含一亿个元素的列表,Python首先会在内存中开辟足够的空间来存储这个包含一亿个元素的列表,然后才允许用户去使用这个列表,这就可能会导致以下问题:

  1、内存中没有足够的内存空间开存储这个列表,从而导致列表无法创建

  2、即使列表成功创建,然而仍会消耗很长的时间,导致程序效率低下

  3、若用户只想访问列表前面的几个元素,则后面列表绝大多数元素占用的空间就都白白浪费了

为了有效解决以上的问题,Python中引入了一种“一边循环,一边计算”的新机制,即当用户需要使用某个对象时,Python才根据事先设计好的规则开辟内存空间创建这个对象供用户使用,而不是像列表一样事先将所有的对象都创建完毕之后再提供给用户使用。这种机制在Python中成为生成器(generator)。

二、生成器的创建

A、生成器推到式

与列表推到式类似,只不过生成器推导式使用()而非[],并且最终返回的是生成器而非列表

 g=((i+2)**2 for i in range(2,30)) #g是一个生成器
print(g) #g为空,里面包含任何元素

B、yield关键字

在一个函数定义中包含yield关键字,则这个函数就不再是一个普通的函数,而是一个生成器(generator)

[说明]:yield指令可以暂停一个函数并返回其中间结果,使用该指令的函数将保存执行环境,并在必要时恢复

 def fib(max):
n,a,b=0,0,1
while n<max:
#print(b)
yield b
a,b=b,a+b
n+=1
return 'done' f=fib(6)
print(f)

[注]:普通函数和变成生成器的函数的不同:

普通函数是顺序执行的,遇到return或是最后一行函数语句就返回。而变成生成器的函数在每次调用__next__()方法时执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

 f=fib(6)
print(f)
print(f.__next__())
print(f.__next__())
print('暂停一下')
print(f.__next__())
print(f.__next__())

三、生成器方法(参考:伯乐在线)

1.close()方法:手动关闭生成器函数,后面的调用会直接返回StopIteration异常

 def func():
yield 1
yield 2
yield 3 g=func()
g.__next__()
g.close() #手动关闭生成器
g.__next__() #关闭后,yield 2和yield 3语句将不再起作用

 2.__next__()方法:返回生成器的下一次调用

 def func():
n=1
for i in range(3):
yield n
n+=1 c=func()
a1=c.__next__()
a2=c.__next__()
a3=c.__next__()

[流程解释]:

对于普通的生成器,第一个__next__()方法的调用相当于启动生成器,此时会从生成器函数的第一行开始执行,直到第一次执行完yield语句(第四行)后,跳出生成器函数。

当调用第二个__next__()方法后,会重新进入生成器函数,并从yield语句的下一条语句(第五行)开始执行,直到重新运行到yield语句,执行后再次跳出生成器函数。

后面的__next__()方法调用以此类推

3.send()方法:接受外部传入的一个变量,并根据变量内容计算结果返回到生成器函数中

[注]:

(1)send()方法和__next__()方法相似,区别在于send()方法可以传递给yield表达式值,而__next__()方法不能传递特定的值,只能传递None给yield表达式,因此可以将generator.__next__()理解为generator.send(None)

(2)第一次调用生成器函数时,必须使用__next__()语句或是send(None),不能使用send发送一个非None的值给生成器函数,否则会出错,因为没有yield语句来接收这个值

 def gen():
value=0
while True:
receive=yield value
if receive=='end':
break
value='Got:%s' %receive g=gen()
print(g.__next__()) #或是print(g.send(None)),从而启动生成器
print(g.send('aaa'))
print(g.send(3))
print(g.send('end'))

[流程解释]:

a.通过g.send(None)或g.__next__()启动生成器函数,并执行到第一个yield语句结束的位置并将函数挂起。此时执行完了yield语句,但是没有给receive赋值,因此yield value会输出value的初始值0

b.g.send('aaa')先将字符串‘aaa’传入到生成器函数中并赋值给receive,然后从yield语句的下一句重新开始执行函数(第五句),计算出value的值后返回到while头部开始新一轮的循环,执行到yield value语句时停止,此时yield value会输出‘Got:aaa’,然后挂起

c.g.send(3)重复步骤b,最后输出结果为‘Got:3'

d.g.send('end')会使程序执行break然后跳出循环,从而函数执行完毕,得到StopIteration异常

4.throw()方法:向生成器发送一个异常。

 def gen():
while True:
try:
yield 'normal value' #返回中间结果,此处的yield和return的功能相似
yield 'normal value2'
print('I am here')
except ValueError:
print('We got ValueError')
except Exception:
print('Other errors')
break g=gen()
print(g.__next__())
print(g.throw(ValueError))
print(g.__next__())
print(g.throw(TypeError))

[解释]:

a.print(g.__next__())会输出normal value,并停在yield 'normal value2'之前

b.由于执行了g.throw(ValueError),所以回跳过后续的try语句,即yield ‘normal value2’不会执行,然后进入到except语句,打印出‘We got ValueError’。之后再次进入到while语句部分,消耗一个yield,输出normal value

c.print(g.__next__())会执行yield ‘normal value2’语句,并停留在执行完该语句后的位置

d.g.throw(TypeError)会跳出try语句,因此print('I am here')不会被执行,然后打印‘Other errors’,并执行break语句跳出while循环,然后到达程序结尾,打印StopIteration异常的信息

四、生成器的运用

 import time
def consumer(name):
print('%s准备吃包子啦!' %name)
while True:
baozi=yield #接收send传的值,并将值赋值给变量baozi
print('包子[%s]来了,被[%s]吃了!' %(baozi,name)) def producer(name):
c1=consumer('A') #把函数变成一个生成器
c2=consumer('B')
c1.__next__()#调用这个方法会走到yield处暂时返回
c2.__next__()
print('开始准备做包子啦!')
for i in range(10):
time.sleep(1)
print('做了一个包子,分成两半')
c1.send(i)
c2.send(i) producer('Tomwenxing')

Python:生成器的简单理解的更多相关文章

  1. python中HTMLParser简单理解

    找一个网页,例如https://www.python.org/events/python-events/,用浏览器查看源码并复制,然后尝试解析一下HTML,输出Python官网发布的会议时间.名称和地 ...

  2. Python中的yield生成器的简单介绍

    Python yield 使用浅析(整理自:廖 雪峰, 软件工程师, HP 2012 年 11 月 22 日 ) 初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关 ...

  3. python——生成器

    python——生成器 通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个 ...

  4. python 生成器和迭代器

    迭代器协议 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就引起一个Stoplteration异常,以终止迭代(只能往后走不能往前退) 2.可迭代对象:实现了 ...

  5. python 生成器 迭代器

    阅读目录 一 递归和迭代 二 什么是迭代器协议 三 python中强大的for循环机制 四 为何要有for循环 五 生成器初探 六 生成器函数 七 生成器表达式和列表解析 八 生成器总结 一 递归和迭 ...

  6. 用Python写一个简单的Web框架

    一.概述 二.从demo_app开始 三.WSGI中的application 四.区分URL 五.重构 1.正则匹配URL 2.DRY 3.抽象出框架 六.参考 一.概述 在Python中,WSGI( ...

  7. Deep learning:四十二(Denoise Autoencoder简单理解)

    前言: 当采用无监督的方法分层预训练深度网络的权值时,为了学习到较鲁棒的特征,可以在网络的可视层(即数据的输入层)引入随机噪声,这种方法称为Denoise Autoencoder(简称dAE),由Be ...

  8. Python中文字符的理解:str()、repr()、print

    Python中文字符的理解:str().repr().print 字数1384 阅读4 评论0 喜欢0 都说Python人不把文字编码这块从头到尾.从古至今全研究通透的话是完全玩不转的.我终于深刻的理 ...

  9. 【python进阶】深入理解系统进程2

    前言 在上一篇[python进阶]深入理解系统进程1中,我们讲述了多任务的一些概念,多进程的创建,fork等一些问题,这一节我们继续接着讲述系统进程的一些方法及注意点 multiprocessing ...

随机推荐

  1. Delphi高效定制格式的FormatDateTime

    本人根据歼10博主的此博文的思路进行改进,目的是高效的实现FormatDateTime('YYYY-MM-DD HH:NN:SS.ZZZ', Now); 在DelphiXE3 32Bits环境测试10 ...

  2. hadoop分布式安装及其集群配置笔记

    各机器及角色信息: 共10台机器,hostname与ip地址映射在此不做赘述.此为模拟开发环境安装,所以不考虑将NameNode和SecondaryNameNode安装在同一台机器. 节点 角色 na ...

  3. 树莓3B+_apt-get update && apt-get upgrade

    在Windows下安装软件,我们只需要有EXE文件,然后双击,下一步直接OK就可以了.但在LINUX下,不是这样的.每个LINUX的发行版,都会维护一个自己的软件仓库,我们常用的几乎所有软件都在这里面 ...

  4. python 数据类型、进制转换

    数据类型 存储单位 最小单位是bit,表示二进制的0或1,一般写作b 最小的存储单位是字节,用byte表示,1B = 8b 1024B = 1KB 1024KB = 1MB 1024MB = 1GB ...

  5. 局域网,Internet,广域网

    局域网:覆盖范围小,自己花钱买设备,带宽固定,自己单位维护 网线100米以内 带宽10m 100m 1000m Internet:ISP,自己的机房,对网民提供访问Internet连接 广域网:距离远 ...

  6. 创建自定义view(翻译 androidtraining)

    创建自定义view 一个设计良好的的自定义view应该是一个设计良好的class,它包含了很多实用的功能,让人们更加容易使用接口.它充分利用GPU与内存的性能等等. 另外作为一个设计良好的类,一个自定 ...

  7. js判断两个日期是否相等的方法

    今天优化代码的时候,发现一个问题,js比较日期是否相等时,我用==去比较,发现两个时间不相等但是运行结果却是true,然后去百度了下发现oldStartTime, startTime都是对象,类型为引 ...

  8. 20155222 2016-2017-2 《Java程序设计》实验三

    20155222 2016-2017-2 <Java程序设计>实验三 1 在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Code菜单 ...

  9. 20155224聂小益的Linux学习

    20155224聂小益的虚拟机安装 虚拟机安装 一开始,我在下载VirtulBox及Ubuntu遇到了一些困难,老实说点进去看到一大堆英文界面的时候真的是有点吓到.不过几秒钟之后就发现这并没有什么哈哈 ...

  10. 20155315 2016-2017-2《Java程序设计》课程总结

    学号 2016-2017-2<Java程序设计>课程总结 每周作业链接汇总 预备作业1:第一次写博客,也是第一次用Markdown,具体流程都还不是很熟悉 预备作业2:对做中学的理解及对c ...