python学习9-生成器(转载)
什么是生成器?
生成器的实质就是迭代器,我们能够从生成器中一个一的拿值
python中获取生成器的方式有三种:
1、通过生成器函数
2、通过生成器表达式
3、通过数据转换也可以获取生成器(某些对象执行一个方法就能返回一个生成器,这个现在用不到)
一、 生成器函数
1 def gen():
2 代码块
3 yield 返回值
4
5 gen() #表示获取一个生成器,是一个内存地址,装的是代码,并不执行,用的时候才会执行
将return换成yield就是生成器函数了,上面就是生成器函数的格式。yield的作用是代码执行到这里就会停止,并且会返回一个值,所以代码能够分段执行,这就是生成器能逐个拿值的原因。
对于生成器函数,函数名+()并不表示函数执行,而是获取一个生成器对象。生成器装的是代码,只有在需要拿值的时候才会执行,这是生成器的惰性机制。
1、通过__next__访问生成器
# def gen():
# print("娃哈哈")
# yield '爽歪歪'
# print("酸酸乳")
# yield 'AD钙奶'
# print('黄焖鸡米饭')
#
# ret = gen() #获取生成器对象,生成器装的是代码,要的时候运行一段
# print(ret) #<generator object gen at 0x0000000001E12F10> 生成器 generator
# print(ret.__next__()) #调用__next__才会执行,返回爽歪歪
# print(ret.__next__()) #调用__next__才会执行,返回Ad钙奶
#print(ret.__next__()) #StopIteration 迭代器,就找yield,找不到就会报错 往下运行,打印出了“黄焖鸡米饭”,但是找不到yield,所以报错
__next__()

1 # def gen():
2 # print("娃哈哈")
3 # yield '爽歪歪'
4 # print("酸酸乳")
5 # yield 'AD钙奶'
6 # print('黄焖鸡米饭')
7 #
8 # ret = gen() #获取生成器对象,生成器装的是代码,要的时候运行一段
9 # print(ret) #<generator object gen at 0x0000000001E12F10> 生成器 generator
10 # print(ret.__next__()) #调用__next__才会执行,返回爽歪歪
11 # print(ret.__next__()) #调用__next__才会执行,返回Ad钙奶
12 #print(ret.__next__()) #StopIteration 迭代器,就找yield,找不到就会报错 往下运行,打印出了“黄焖鸡米饭”,但是找不到yield,所以报错

2、通过send()访问生成器
send()可以取值的同时给上一个yield位置传值
def func():
print("水饺")
a = yield "大馅水饺"
print("a=", a)
print("烧饼")
b = yield "武大郎烧饼"
print("b=", b)
print("老婆饼")
c = yield "只要老婆不要饼"
print("c =",c)
g = func()
print("返回值是:",g.__next__())
print("返回值是:",g.send("面条"))
print("返回值是:",g.send("面条"))
#print("返回值是:",g.send("面条")) #c = 面条 报错 StopIteration
#结果
水饺
返回值是: 大馅水饺
a= 面条
烧饼
返回值是: 武大郎烧饼
b= 面条
老婆饼
返回值是: 只要老婆不要饼
send()

1 def func():
2 print("水饺")
3 a = yield "大馅水饺"
4 print("a=", a)
5 print("烧饼")
6 b = yield "武大郎烧饼"
7 print("b=", b)
8 print("老婆饼")
9 c = yield "只要老婆不要饼"
10 print("c =",c)
11
12 g = func()
13 print("返回值是:",g.__next__())
14 print("返回值是:",g.send("面条"))
15 print("返回值是:",g.send("面条"))
16 #print("返回值是:",g.send("面条")) #c = 面条 报错 StopIteration
17
18 #结果
19 水饺
20 返回值是: 大馅水饺
21 a= 面条
22 烧饼
23 返回值是: 武大郎烧饼
24 b= 面条
25 老婆饼
26 返回值是: 只要老婆不要饼

send和__next__的区别:
send()和__next__都可以让生成器向下走一段,但send可以给上一个yield位置传值,使用时不能在第一次,也不能给最后一个yield传值
二、推导式
1、列表推导式
语法:[ 结果 for循环 if判断 ]
1 lst = ["中岛美雪","夏川美里","原由子","汪峰","田震","那英","周杰伦"]
2
3 l = [name for name in lst if len(name) == 2 ] #这就是列表推导式
4 print(l)
1 lst = ["中岛美雪","夏川美里","原由子","汪峰","田震","那英","周杰伦"]
2
3 l = [name for name in lst if len(name) == 2 ] #这就是列表推导式
4 print(l)
2、字典推导式
语法:{ key:value for循环 if判断 }
dic ={"张无忌":"赵敏","杨过":"小龙女","郭靖":"黄蓉"}
new_dic = {dic[k]: k for k in dic} #字典推导式
print(new_dic)
new = {v:k for k,v in dic.items()} #字典推导式
print(new)
dic ={"张无忌":"赵敏","杨过":"小龙女","郭靖":"黄蓉"}
new_dic = {dic[k]: k for k in dic} #字典推导式
print(new_dic)
new = {v:k for k,v in dic.items()} #字典推导式
print(new)
3、集合推导式
语法:{ 结果 for循环 if判断 }
lst = [1,2,3,1,2,4]
se = {k for k in lst} #这是集合推导式
print(se) # {1,2,3,4}
lst = [1,2,3,1,2,4]
se = {k for k in lst} #这是集合推导式
print(se) # {1,2,3,4}
集合推导式自带去重功能
5、没有元组推导式
6、生成器表达式
语法:( 结果 for循环 if判断 )
names = [['Tom',"Billy","Jefferson","Abdrew","Wesley","Steven","Joe"],['Alice',"Jill","Ana","Wendy",'Jennifer','Sherry','Eva']]
name_gen = (name for el in names for name in el if name.count("e")==2)
print(name_gen.__next__())
print(name_gen.__next__())
print(name_gen.__next__())
结果
#Jefferson
#Wesley
#Steven
生成器表达式

1 names = [['Tom',"Billy","Jefferson","Abdrew","Wesley","Steven","Joe"],['Alice',"Jill","Ana","Wendy",'Jennifer','Sherry','Eva']]
2
3 name_gen = (name for el in names for name in el if name.count("e")==2)
4 print(name_gen.__next__())
5 print(name_gen.__next__())
6 print(name_gen.__next__())
7
8
9 结果
10 #Jefferson
11 #Wesley
12 #Steven

生成器拿值方式:
1、用__next__和send
2、使用for循环
1 gen = (i for i in range(1,100) if i % 3 == 0)
2 for num in gen:
3 print(num)
3、list(g),g是生成器
1 gen = (i * i for i in range(100) if i % 3 == 0)
2 print(list(gen))
结果是一个列表
[0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304, 2601, 2916, 3249, 3600, 3969, 4356, 4761, 5184, 5625, 6084, 6561, 7056, 7569, 8100, 8649, 9216, 9801]
生成器的特性:
1、节省内存
2、惰性机制 (不到最后使用时不会拿值)
3、拿值只能往前,不能后退
惰性机制+只能往前拿值特性的组合考察(深坑):

def func():
print(111)
yield 222
g = func() # 生成器g
g1 = (i for i in g) # 生成器g1. 但是g1的数据来源于g
g2 = (i for i in g1) # 生成器g2. 来源g1
print(list(g)) # 获取g中的数据. 这时func()才会被执行. 打印111.获取到222. g完毕.
print(list(g1)) # 获取g1中的数据. g1的数据来源是g. 但是g已经取完了. g1 也就没有数据
了
print(list(g2)) # 和g1同理 #结果
111
222
[]
[]

**小知识 yield from**
yield ffrom 可以直接把可迭代对象中的每一个数据作为生成器的结果进行返回
def gen():
lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
yield from lst
g = gen() #获取生成器
for el in g:
print(el)
等价于:
def gen():
lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
yield lst[0]
yield lst[0]
yield lst[0]
yield lst[0]
g = gen() #获取生成器
for el in g:
print(el)
yield from

def gen():
lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
yield from lst g = gen() #获取生成器
for el in g:
print(el) 等价于:
def gen():
lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
yield lst[0]
yield lst[0]
yield lst[0]
yield lst[0]
g = gen() #获取生成器
for el in g:
print(el)

**面试题**
1、

def gen():
lst = ["花藤", "胡辣汤", "微星牌饼铛", "Mac牌锅铲"]
lst2 = ["饼铛还是微星的好", "联想不能煮鸡蛋", "微星就可以", "还可以烙饼"]
yield from lst #yield from 会迭代返回列表中的元素,执行完lst才会执行lst2,所以不会有交替打印的效果
yield from lst2
g = gen()
for el in g:
print(el)
效果:
花藤
胡辣汤
微星牌饼铛
Mac牌锅铲
饼铛还是微星的好
联想不能煮鸡蛋
微星就可以
还可以烙饼

2、

def add(a,b):
return a + b
def test():
for r_i in range(4):
yield r_i
g = test()
for n in [2,10]:
g = (add(n,i) for i in g)
print(list(g))
#for循环第一次执行,n= 2时 g变为了 g = add(n,i) for i in (add(n,i) for i in test() 这时没取值,g也就不执行
# for第二次执行,n=10 此时 g= add(n,i) for i in (add(n,i) for i in test() 这时开始取值 ,g执行 结果:
[20, 21, 22, 23]

python学习9-生成器(转载)的更多相关文章
- python学习之生成器
4.6 生成器Generrator 生成器本质就是迭代器.python社区生成器与迭代器是一种. 生成器与迭代器的唯一区别:生成器是我们自己用python代码构建的 4.6.1生成器初识 py ...
- Python学习二(生成器和八皇后算法)
看书看到迭代器和生成器了,一般的使用是没什么问题的,不过很多时候并不能用的很习惯 书中例举了经典的八皇后问题,作为一个程序员怎么能够放过做题的机会呢,于是乎先自己来一遍,于是有了下面这个ugly的代码 ...
- python学习之---生成器
通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含1000万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元 ...
- 《Python 二三事》——python学习必看(转载)
面向初学者介绍Python相关的一些工具,以及可能遇到的常见问题. 原文出处 原文作者:八八年出生的男性,互联网上常用id是 jagttt .目前正从事 IT 行业的工作.业余爱好是动漫游加电 ...
- Python学习笔记 - 生成器generator
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # generator 生成器 L = [x * x for x in range(10)] print( ...
- Python学习——迭代器&生成器&装饰器
一.迭代器 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素.迭代器仅 ...
- python学习-39 生成器总结
总结 1.语法上和函数类似:生成器函数和常规函数几乎是一样的.它们都是使用def语句进行定义,差别在于,生成器使用yield语句返回一个值,常规函数使用return语句返回一个值. 2.自动实现迭代器 ...
- Python学习笔记——Day5(转载)
python 编码转换 主要介绍了python的编码机制,unicode, utf-8, utf-16, GBK, GB2312,ISO-8859-1 等编码之间的转换. 常见的编码转换分为以下几种情 ...
- python学习2(转载)
一.流程控制之while循环 语法:while 条件: 循环体else: else语句(当条件不成立的时候执行这里 和break没关系) 判断条件是否成立. 如果成立执行循环体.然后再次判断条件,.. ...
- python学习之- 生成器/迭代器
列表生成式写法: [ i*2 for i in range(10) ]也可以带函数 [ fun(i) for i in range(10) ] 生成器:一边循环一边计算的机制称为生成器.在常用函数中, ...
随机推荐
- Gson 配置解析
之前项目用到了gson对json和Java类之间互转,现在将gson的配置总结一下. 首先,创建gson对象之间,建立gsonbuilder对象,并配置 // 不导出实体类中没有用@Expose注解的 ...
- (转)Asp.Net生命周期系列三
原文地址:http://www.cnblogs.com/skm-blog/p/3178862.html 上文讲到了HttpRunTime主要做了三个事情,我们先回忆一下. 第一:雇佣了项目经理(Htt ...
- Schwartz kernel theorem施瓦兹核定理
In mathematics, the Schwartz kernel theorem is a foundational result in the theory of generalized fu ...
- FileTracker:error FTK1011编译错误的原因和解决办法
原因: 今天创建好项目名字完成关了VS,后感觉文件夹名字不太对改了一下,后来程序就调试不了出现FileTracker:error FTK1011编译错误0.0,经过网络查询应该是路径问题 解决方法: ...
- 苹果微信内置浏览器cookie
苹果微信内置浏览器cookie会被自动清掉,但safari不会清除,原因还未找到,解决方法是把前端把数据通过header传到后台
- VM12安装Mac系统操作指南
1.第一步,操作按照这个链接来搞 VMware 12安装Mac OS 系统使用的是 OS X 10.11.1(15B42) 2.激活工具一定要使用 unlocker208 3.初次安装可能存在的报错 ...
- [SinGuLaRiTy] 2017 百度之星程序设计大赛 初赛B
[SinGuLaRiTy-1037] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. Chess Time Limit: 2000/1000 ...
- 单元测试unittest
unittest.TestSuite():用例集合 uinttest.defaultTestLoader.discover():寻找测试用例,去哪个目录下寻找测试用例,加载测试用例
- LoadRunner11_录制脚本时的浏览器版本
最近在做的项目,因为浏览器类型及版本问题,浪费了很多时间,现在就此次的小折腾做一个小结,方便后期录制时选择(如果自己写脚本,那就可以完全忽略这些啦): (1)IE:win7 32位LR11.0,最 ...
- oracle查询分区表中的数据
select * from TABLE_NAME partition(分区名) T WHERE T.COL_NAME= 'XX';