一、生成器

生成器总结
语法上和函数类似:生成器函数和常规函数几乎是一样的。他们都是使用def语句进行定义,差别在于生成器使用yield语句返回一个值,而常规函数使用return语句返回一个值。自动实现迭代器协议;对于生成器,python会自动实现迭代器协议,以便应用到迭代背景种,(如for循环,sum函数)。由于生成器自动实现了迭代器协议,所以,我们可以调用它的next方法,并且,在没有值可以返回的时候,生成器自动产生stop iteration异常。

状态挂起:生成器使用yield语句返回一个值,yield语句挂起该生成器函数的状态,保留足够的信息,以便之后从他离开的地方继续执行。

1、初识

 gift_list = ('礼盒%s'%i for i in range(10))   #这就是生成器表达式
print(gift_list)
print(gift_list.__next__())
print(next(gift_list))
 <generator object <genexpr> at 0x00000294B972DDB0>
礼盒0
礼盒1

2、

 import time
def test():
print('桃树准备开花了')
time.sleep(1)
yield '长了第一个桃子'
time.sleep(1)
print('把第一个桃子吃了')
time.sleep(1)
yield '长了第二个桃子'
print('把第二个桃子吃了')
yield '长了第三个桃子' res = test()
print(res)
print(res.__next__()) #这次执行yield就会停在那里。下一次执行next就从上一次yield的地方开始执行。
print(next(res))
print(res.__next__())
 <generator object test at 0x00000121469BA308>
桃树准备开花了
长了第一个桃子
把第一个桃子吃了
长了第二个桃子
把第二个桃子吃了
长了第三个桃子

3、卖包子的例子

 def produce_baozi():
for i in range(1,11):
print('准备生产包子')
yield '一笼包子%i'%i
print('开始卖包子')
p_baozi = produce_baozi()
print(p_baozi.__next__())
print(p_baozi.__next__())
 准备生产包子
一笼包子1
开始卖包子
准备生产包子
一笼包子2

4、产鸡蛋的例子

 def produce_egg():
ret = []
for i in range(1,11):
ret.append('鸡蛋-%s'%i)
return ret p_egg = produce_egg()
print(p_egg) 这种方式 占空间大,效率低 def produce_egg():
for i in range(1,11):
yield 'egg-%s'%i
chicken = produce_egg()
print(chicken.__next__())
print(chicken.__next__())
print(chicken.__next__())
print(next(chicken))
print(next(chicken)) for egg in chicken:
print(egg)
 ['鸡蛋-1', '鸡蛋-2', '鸡蛋-3', '鸡蛋-4', '鸡蛋-5', '鸡蛋-6', '鸡蛋-7', '鸡蛋-8', '鸡蛋-9', '鸡蛋-10']
egg-1
egg-2
egg-3
egg-4
egg-5
egg-6
egg-7
egg-8
egg-9
egg-10

优点一:生成器的好处是延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果。这对于大数据量处理,将会非常有用。

列表解释
sum((i for i in range(1000000000))  #内存占用大,机器容易卡死

生成器表达式
sum(i for i in range(1000000000))  #几乎不占内存

优点二:生成器还能有效提高代码可读性

这里,至少有两个充分的理由说明,使用生成器比不使用代码更加清晰:
    1、使用生成器以后,代码行数更少。大家要记住,如果想要把代码写的pythonic在保证代码可读性的前提下,代码行数越少越好。
    2、不使用生成器的时候,对于每次结果,我们首先看到的是result append(index),其次,才是index。也就是说,我们每次看到的是一个列表的append的操作      的,知识append的是我们想要的结果。使用生成器时候,直接yield index,少了列表append操作的干扰,我们一眼就能够看出,代码是要返回index。
    
    上面的例子充分说明了,合理使用生成器,能够有效提高代码可读性,只要大家完全接收了生成器的概念,理解了yield语句和return语句一样,业绩是返回一个值。
    那么,就能够理解为什么使用生成器比不适用生成器要好,能够 理解使用生成器真的可以让代码变得清晰易懂。

二、通过生成器实现协程并行运算

例1

 def consumer(name):
print('%s开始准备吃包子了'%name)
while True:
baozi = yield 1
print('包子%s被%s吃完了'%(baozi,name)) def producer(name):
c = consumer('A')
c2 = consumer('B')
print(c.__next__())
print(c2.__next__())
print('大爷要吃包子啦')
for i in range(1,11):
c.send(i)
c2.send(i)
producer('隔壁老王')
 A开始准备吃包子了
1
B开始准备吃包子了
1
大爷要吃包子啦
包子1被A吃完了
包子1被B吃完了
包子2被A吃完了
包子2被B吃完了
包子3被A吃完了
包子3被B吃完了
包子4被A吃完了
包子4被B吃完了
包子5被A吃完了
包子5被B吃完了
包子6被A吃完了
包子6被B吃完了
包子7被A吃完了
包子7被B吃完了
包子8被A吃完了
包子8被B吃完了
包子9被A吃完了
包子9被B吃完了
包子10被A吃完了
包子10被B吃完了

例2

 import time
def consumer(name):
print('我是[%s],我准备开始吃包子了' %name)
while True:
baozi=yield
time.sleep(1)
print('%s 很开心的把【%s】吃掉了' %(name,baozi)) def producer():
c1=consumer('隔壁老王')
c2=consumer('对面老李')
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
c1.send('包子 %s' %i)
c2.send('包子 %s' %i)
producer()
 我是[隔壁老王],我准备开始吃包子了
我是[对面老李],我准备开始吃包子了
隔壁老王 很开心的把【包子 0】吃掉了
对面老李 很开心的把【包子 0】吃掉了
隔壁老王 很开心的把【包子 1】吃掉了
对面老李 很开心的把【包子 1】吃掉了
隔壁老王 很开心的把【包子 2】吃掉了
对面老李 很开心的把【包子 2】吃掉了
隔壁老王 很开心的把【包子 3】吃掉了
对面老李 很开心的把【包子 3】吃掉了
隔壁老王 很开心的把【包子 4】吃掉了
对面老李 很开心的把【包子 4】吃掉了
隔壁老王 很开心的把【包子 5】吃掉了
对面老李 很开心的把【包子 5】吃掉了
隔壁老王 很开心的把【包子 6】吃掉了
对面老李 很开心的把【包子 6】吃掉了
隔壁老王 很开心的把【包子 7】吃掉了
对面老李 很开心的把【包子 7】吃掉了
隔壁老王 很开心的把【包子 8】吃掉了
对面老李 很开心的把【包子 8】吃掉了
隔壁老王 很开心的把【包子 9】吃掉了
对面老李 很开心的把【包子 9】吃掉了

例3

 import time
def producer():
ret=[]
for i in range(10):
time.sleep(0.1)
ret.append('包子%s' %i)
return ret def consumer(res):
for index,baozi in enumerate(res):
time.sleep(0.1)
print('第%s个人,吃了%s' %(index,baozi)) res=producer()
consumer(res)
 第0个人,吃了包子0
第1个人,吃了包子1
第2个人,吃了包子2
第3个人,吃了包子3
第4个人,吃了包子4
第5个人,吃了包子5
第6个人,吃了包子6
第7个人,吃了包子7
第8个人,吃了包子8
第9个人,吃了包子9
yield 3相当于return 控制的是函数的返回值
x=yield的另外一个特性,接受send传过来的值,赋值给x

例4

 def test():
print('开始啦')
firt=yield #return 1 first=None
print('第一次',firt)
yield 2
print('第二次') t=test()
res=t.__next__() #next(t)
print(res)
# t.__next__()
# res=t.send(None)
res=t.send('函数停留在first那个位置,我就是给first赋值的')
print(res)
 开始啦
None
第一次 函数停留在first那个位置,我就是给first赋值的
2

十八、python沉淀之路--生成器的更多相关文章

  1. 十、python沉淀之路--高阶函数初识

    一.高阶函数:分两种:一种是返回值中包含函数体:另一种是把一个函数体当作了参数传给了另一个函数 1.返回值中包含函数体 例1. def test(): print('这是一个测试') return t ...

  2. 十八. Python基础(18)常用模块

    十八. Python基础(18)常用模块 1 ● 常用模块及其用途 collections模块: 一些扩展的数据类型→Counter, deque, defaultdict, namedtuple, ...

  3. 十六、python沉淀之路--迭代器

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

  4. 十五、python沉淀之路--eval()的用法

    一.eval函数 python eval() 函数的功能:将字符串str当成有效的表达式来求值并返回计算结果. 语法:eval(source[, globals[, locals]]) -> v ...

  5. 十九、python沉淀之路--装饰器

    一.实现装饰器的预备知识 装饰器 = 高阶函数 + 函数嵌套 + 闭包 1.高价函数定义: 1.函数接收的参数是一个函数名    2.函数的返回值是一个函数名    3.满足上述条件任意一个,都可称之 ...

  6. 十四、python沉淀之路--文件操作

    一.文件操作b模式 1. # f = open('test11.py','rb',encoding='utf-8') # 这种情况会报错 f = open('test11.py','rb') # b ...

  7. 十二、python沉淀之路--内置函数

    1.abs函数,求绝对值. a = abs(-3) print(a) 返回:3 2.all函数:判断是否是可迭代对象. 官方解释:Return True if bool(x) is True for ...

  8. 七、python沉淀之路--集合

    一. 1.字符串转集合 s = 'hello' se = set(s) print(se) {'e', 'o', 'h', 'l'} 2.列表转集合 l1 = ['hello','python','n ...

  9. Python3.5学习十八 Python之Web框架 Django

    Python之Web框架: 本质:Socket 引用wsgiref创建web框架 根据web框架创建过程优化所得: 分目录管理 模板单独目录 执行不同函数单独存入一个方法py文件 Web框架的两种形式 ...

随机推荐

  1. 20165101刘天野 2018-2019-2《网络对抗技术》Exp3 免杀原理与实践

    20165101刘天野 2018-2019-2<网络对抗技术>Exp3 免杀原理与实践 1. 实践内容 1.1 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil- ...

  2. 20145109《Java程序设计》第一周学习总结

    20145109 <Java程序设计>第一周学习总结 教材学习内容总结 About JVM, JRE, JDK JVM包含于JRE中,用于运行Java程序.JDK用于开发Java程序,包含 ...

  3. docker 使用mysql

    mysql 5.7安装成功了,之前5.6一直报错不知道为什么 sudo docker run --name emall_mysql -e MYSQL_ROOT_PASSWORD=jbt1234 -e ...

  4. 基于主从复制的Mysql双机热备+amoeba实现读写分离、均衡负载

    读写分离指的是客户只能在主服务器上写,只能在从服务器上读,当然了,这也是要看配置,你可以在主服务器配置读的功能,但是在从服务器上只能读不能写,因为从服务器是基于binlog对主服务器的复制,如果在从服 ...

  5. 利用正则提取discuz的正文内容

    源正文: [p=24, null, left][color=#000][font=宋体]近日,香港著名漫画家马荣成在香港举办的"[color=#ff660][url=http://cul.c ...

  6. eclipse——JavaEE插件

    步骤如下 1.先看自己的eclipse版本 2.开始安装JavaEE插件 http://download.eclipse.org/releases/Photon 注意:这里后面红色的是博主eclips ...

  7. java父类调用被子类重写的方法

    [转][原文]  1.如果父类构造器调用了被子类重写的方法,且通过子类构造函数创建子类对象,调用了这个父类构造器(无论显示还是隐式),就会导致父类在构造时实际上调用的是子类覆盖的方法(你需要了解jav ...

  8. codeforces 820A. Mister B and Book Reading 解题报告

    题目链接:http://codeforces.com/problemset/problem/820/A 坑爹题目,坑爹题目,坑爹题目....汗 = =!  后台还110个 test 有个地方需要注意下 ...

  9. 使用SpringMVC的crud操作时,进行数据修改,但是修改成功后,页面无法显示lastName属性值(被修改的那条记录)

    我这个错误的原因在于,把map的键写错了,它必须和类名第一个字母小写相同 @ModelAttribute public void getEmployee(@RequestParam(value=&qu ...

  10. 在mybatis中使用存储过程报错java.sql.SQLException: ORA-06550: 第 1 行, 第 7 列: PLS-00905: 对象 USER1.HELLO_TEST 无效 ORA-06550: 第 1 行, 第 7 列:

    hello_test是我的存储过程的名字,在mapper.xml文件中是这么写的 <select id="getPageByProcedure" statementType= ...