生成器
一.生成器
生成器的实质就是迭代器
1.1 获取方式
1.通过生成器函数
2.通过各种推导式来实现生成器
3.通过数据的转化也可以获取
简单的函数一目了然
def fun()
print()
return 222
ret = fun()
print (ret)
输出结果
111
222
将函数中的return换成yied就是生成器
def fun():
print("111")
yied 222
ret = func()
print()
结果:
<generator object func at 0x10567ff68>
运行结果是一个地址为什么呢??
想一想迭代器的惰性要使用__next__来去执行
def func():
print("111")
yield 222
gener = func() # 这个时候函数不不会执⾏行行. ⽽而是获取到⽣生成器器
ret = gener.__next__() # 这个时候函数才会执⾏行行. yield的作⽤用和return⼀一样. 也是返回
数据
print(ret)
结果:
111
222
我们可以看出yied 的作用和return 有点相似那么她俩的去别是就是return是直接退出,而yied是继续进行遇到下一个yied 的时候继续执行
def func():
print("111")
yield 222
print("333")
yield 444
gener = func()
ret = gener.__next__()
print(ret)
ret2 = gener.__next__()
print(ret2)
ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也就是
说. 和return⽆无关了了.
print(ret3)
结果:
111
Traceback (most recent call last):
222
333
File "/Users/sylar/PycharmProjects/oldboy/iterator.py", line 55, in
<module>
444
ret3 = gener.__next__() # 最后⼀一个yield执⾏行行完毕. 再次__next__()程序报错, 也
就是说. 和return⽆无关了了.
StopIteration
生成器的作用
生成器在编程中有什么作用呢?假如你要调用一个庞大的数据那么如果你一次性掉出来的时候会撑爆内存的
所以这个时候用yield 就会变得很容易的, 我们可以分批去调用
接下来我们来介绍一个send 的用法
def eat(): print("我吃什什么啊") a = yield "馒头" print("a=",a) b = yield "⼤大饼" print("b=",b) c = yield "⾲韭菜盒⼦子" print("c=",c) yield "GAME OVER" gen = eat() # 获取⽣生成器器 ret1 = gen.__next__() print(ret1) ret2 = gen.send("胡辣汤") print(ret2) ret3 = gen.send("狗粮") print(ret3) ret4 = gen.send("猫粮") print(ret4)
输出的结果
我吃什什么啊
馒头
a= 胡辣汤
⼤大饼
b= 狗粮
⾲韭菜盒⼦子
c= 猫粮
GAME OVER
来区分一下send 和__next()__:
1.send 和next()都是让生成器向下一次走
2.send可以给上一个yield的位置传值,不能给最后一个yield发送值.在第一次执行生成器代码时不能使用send()
注意的一点就是生成器也可以使用for 循环来获取内部的元素:
def func():
print(111)
yield 222
print(333)
yield 444
print(555)
yield 666
gen = func()
for i in gen:
print(i)
结果:
111
222
333
444
555
666
二 .列表推导式
这个列表推导式是一个很有技术含量的东西,也就是说你要把前面学的遍历的知识搞懂了学推导式就会很容易
来个例子
lst = [] for i in range(1, 15): lst.append(i) print(lst) 输出结果 [1,2,3,4,5,6,7,8,9,10,11,12,13,14] 这个大家很熟悉 但是它还可以有更简便的方法 列表推导式 lst = [i for i in range(1.15)]
print(lst) 输出的结果是 [1,2,3,4,5,6,7,8,9,10,11,12,13,14]
结果一样
格式是:lst = ["你想要的结果"+for循环+判断 ]
对它还可以加判断
# 获取1-100内所有的偶数 lst = [i for i in range(1, 100) if i % 2 == 0] print(lst)
输出的结果
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]
那么除了列表推导式是不是还有字典推导式
对!!
字典推导式跟列表推导式一样不过格式不一样
举个例子
dic = {"jj": "林俊杰", "jay": "周杰伦", "zs": "赵四", "ln":"刘能"}
d = {v : k for k,v in dic.items()}
print(d)
输出的结果是
{'林俊杰': 'jj', '周杰伦': 'jay', '赵四': 'zs', '刘能': 'ln'}
这样是不是会很简单呢.
那么接下来是不是就应该是元组的推导式呢,其实呢元组的表达式就是生成器的推导式元组是没有推导式的
来举个例子你就明白了,有些人那就是不见棺材不落泪
tu = (i for i in range(10)) # 没有元组推导式. 生成器表达式 print(tu) # 生成器 输出的结果是什么?? <generator object <genexpr> at 0x000001E9AE8359E8>
是不是跟你想想的不太一样 给你说了元组没有推导式 就是不相信邪
我们把上面的这个表达式叫做生成器的表达式
tu = (i for i in range(10))
print(tu)
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
print(tu.__next__())
输出的结果是
0
1
2
3
4
5
6
7
8
9
同样生成器的推导式也可以作for 循环还有判断 举个例子
100以内能被3整除的数的平⽅方
gen = (i * i for i in range(100) if i % 3 == 0)
for num in gen:
print(num)
输出结果
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.得到的值不一样.列表推导式得到的是一个列表.生成器表达式获取的是一个生成器.
举个例子 (很经典的例子)
同样一篮子鸡蛋,列表推导式拿到一篮子的鸡蛋,生成器表达式拿到的是一个老母鸡,需要鸡蛋就给你下鸡蛋你不就省了空间去放鸡蛋
所以以后你只要记住老母鸡就能想起生成器表达式
生成器的惰性机制:生成器只有在访问的时候在取值,说白了,你找它要了他在会给你给,你不要他是不会执行的
深坑----->生成器.要值的时候才拿值.
还有一个就是集合的推导式
他与前面提到的一样,我们主要利用集合来取重 举个例子
lst = [1, 1, 4, 6,7,4,2,2]
s = { el for el in lst }
print(s)
输出结果
{1, 2, 4, 6, 7}
生成器表达式和列表推导式的区别:
1.列表推导式比较耗内存,一次性加载.生成器表达式几乎不占内存,使用的时候才分配和使用内存
2.得到的值不一样,列表推导式得到的是一个列表.生成器表达式得到的是一个生成器.
生成器的惰性机制:生成器只有在访问的时候才取值.平常不执行.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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 ] [] [] |
注意:生成器只有在要值的时候才拿值.
推导式有列表推导式,字典推导式,集合推导式,没有元组推导式.
生成器表达式可以直接获取生成器对象,也可以进行for循环.
1
2
3
4
5
6
7
8
9
10
11
12
|
#关于生成器的一个很重要的题 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)) 结果: [ 20 , 21 , 22 , 23 ] |