一,生成器和生成器表达式
什么是生成器,生成器实质就是迭代器,在python中有三种方式来获取生成器:
1. 通过生成器函数
和普通函数没有区别,里面有yield的函数就是生成器函数,生成器函数在执行的时候.,默认不会执行函数体.,返回生成器通过生成器的__next__()分段执行这个函数
send() 给上一个yield传值, 不能再开头(没有上一个yield), 最后一个yield也不可以用send()
先来看一下简单的函数
1 def xue(): #创建一个函数
2 print('学')3 return 'Python' #生成器
4 xue1 =xue()5 print(xue1)6 结果:7 学8 Python
函数中的return换成yield这就是一个生成器
1 defxue():2 print('学')3 yield 'Python'
4 xue1 =xue()5 print(xue1)6 结果:7
运行结果跟上面的不一样,因为由于函数中存在yield,那么这个函数就是一个生成器函数,这个时候我们在执行这个函数的时候,就不再是函数的执行了,而是获取这个生成器,如何使用呢?想想迭代器,生成器的本质就是迭代器,所以,我们可以直接执行__next__()来执行以下生成器
1 defxue():2 print('学')3 yield 'Python'
4 xue1 = xue() #这时候函数不会执行,而是获取到生成器
5 YJ = xue1.__next__()#这个时候函数才会执⾏行yield的作⽤用和return一样. 也是返回数据
6 print(YJ)7 结果:8 学9 Python
yield和return的区别就是,yield是分段来执行一个函数,return是直接停止执行函数
1 defxue():2 print('学')3 yield 'Python'
4 print('也学')5 yield 'java'
6 xue1 = xue() #这时候函数不会执行,而是获取到生成器
7 YJ = xue1.__next__()8 print(YJ)9 YJ1 = xue1.__next__()10 print(YJ1)11 YJ2 = xue1.__next__() #最后一个yield执行完毕,再次__next__()程序报错,也就是说和return无关了
12 print(YJ2)
结果:
当程序运行完最后一个yield,那么后面继续进行__next__()
需求:某学校要订购50000套校服,工厂直接生产50000套校服,但是学校也没有5000个学生,也没有教室放置一次性生产那么多,最后的效果会是什么呢?直接生产50000件校服,刷一下量大的话把你内存撑满!!!
1 defxiaofu():2 lst =[]3 for el in range(0,50000):4 lst.append('校服'+str(el))5 returnlst6 xiaofu()7 print(xiaofu())
我要一套你给一套,一共50000,是不是很完美
defxiaofu():for el in range(0,50000):yield '校服'+str(i)
xf=xiaofu()print(xf.__next__())print(xf.__next__())print(xf.__next__())print(xf.__next__())
两者的区别,第一种是直接一次性全部拿出来,会很占用内存,第二种是使用生成器,一次就一个,用多少生产多少,直到生产完,生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就指到哪儿,下一次继续获取指针指向的值
send方法,send和__next__()一样都可以让生成器执行到下一个yield
1 defxue():2 print('要学')3 a = yield 'Python'
4 print('a=',a)5 b = yield 'java'
6 print('b=', b)7 c = yield 'PHP'
8 print('c=', c)9 yield 'YJ加油!'
10 xue1 = xue() #获取生成器
11 fh = xue1.__next__()12 print(fh)13 #结果:要学
14 #Python
15 fh1 = xue1.send('VB')16 print(fh1)17 #结果:a= VB
18 #java
19 fh2 = xue1.send('C#')20 print(fh2)21 #结果:b= C#
22 #PHP
23 fh3 = xue1.send('C++')24 print(fh3)25 #结果:c= C++
26 #YJ加油!
send和__next__()的区别
1.send和next()都是让生成器向下走一次
2.send可以给上一个yield的位置传递值,不能给最后一个yield发送值,在第一次执行生成器代码的时候不能使用send()
生成器可以使用for需变换来循环获取内部元素:
1 defxue():2 print('要学')3 a = yield 'Python'
4 print('a=',a)5 b = yield 'java'
6 print('b=', b)7 c = yield 'PHP'
8 print('c=', c)9 yield 'YJ加油!'
10 xue1 =xue()11 for el inxue1:12 print(el)
结果:
2. 通过各种推导式来实现生成器
1. 列表推导式 [结果 for循环 条件筛选]
2. 字典推导式 {k:v for循环 条件筛选}
3. 集合推导式 {k for循环 条件}
3. 通过数据的转换也可以获取生成器
二.,生成器表达式,列表推导式,以及其他推导式
我们来看一段代码,给出一个空列表,通过for循环向列表添加1-15个数字:
1 lst =[]2 for i in ramge(1,16):3 lst.append(i)4 print(lst)5 结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,15]
列表推导式写法:
1 #推导式2 lst = [i for i in range(1,16)]3 print(lst)4 结果:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
两者的结果是不是一样?列表推导式比较简洁,列表推导式是通过一行来构建你要的列表,列表推导式看起来代码简单,但是出现错误之后就很难排查
列表推导式的写法:[结果 for 变量 in 可迭代对象]
需求:从1-19岁写入到lst列表中
1 lst = [str(i)+'岁' for i in range(1,20)]2 print(lst)3 结果:['1岁', '2岁', '3岁', '4岁', '5岁', '6岁', '7岁', '8岁', '9岁', '10岁', '11岁', '12岁', '13岁', '14岁', '15岁', '16岁', '17岁', '18岁', '19岁']
我们还可以对列表中的数据进行筛选,筛选写法:
[ 结果 for 变量 in 可迭代对象 if 条件 ]
#获取1-100内所有的偶数
1 lst = [i for i in range(1,100) if i % 2 ==0]
2 print(lst)
生成器表达式和列表推导式的语法基本是一样的,只是把[]换成()
1 YJ = (i for i in range(1,15))2 print(YJ)3 结果为:4 at 0x000002CE3ABA5660>
上面的结果就是一个生成器,我们可以使用for循环来获取这个生成器
1 YJ = ('我今年%s岁了' % i for i in range(20))2 for i inYJ:3 print(i)4 结果:5 我今年0岁了6 我今年1岁了7 我今年2岁了8 我今年3岁了9 我今年4岁了10 我今年5岁了11 我今年6岁了12 我今年7岁了13 我今年8岁了14 我今年9岁了15 我今年10岁了16 我今年11岁了17 我今年12岁了18 我今年13岁了19 我今年14岁了20 我今年15岁了21 我今年16岁了22 我今年17岁了23 我今年18岁了24 我今年19岁了
生成器表达式也是可以进行筛选的
获取1-100内能被3整除的数
1 #获取1-100内能被3整除的数
2 YJ = (i for i in range(1,100) if i % 3 ==0)3 print(YJ)4 #结果: at 0x000002164AC95660>
5 for i in YJ: #使用for循环来循环这个生成器拿结果
6 print(i)7 结果;8 3,6,9,12,15...99
100以内能被3整除的数的平方
1 YJ = (i * i for i in range(100) if i % 3 ==0)2 for i in YJ: #使用for循环来循环这个生成器拿结果
3 print(i)
生成器表达式跟列表推导式的区别:
1.列表推导式比较耗内存,一次性加载,生成器表达式几乎不占内存,使用的时候才分配和使用内存
2.得到的值不一样,列表推导式得到的是一个列表,生成器表达式获取的是一个生成器
生成器有惰性机制,生成器只有访问的时候才取值,说白了,你找它要它才会给你值,不找不给它也不会执行
字典推导式:
根据名字也能猜到,推到出来的是字典
1 dic = {'a' : 1, 'b' : 2, 'c' : 3}2 dic1 = {dic[key] : key for key indic}3 print(dic1)4 #结果:{1: 'a', 2: 'b', 3: 'c'}
集合推导式:
集合推导式可以帮我们直接生成一个集合,集合的特点是无序,不重复,所有集合推导式自带去重功能
1 lst = [1,1,2,3,3,66,66,8,9]2 a = {abs(i) for i inlst}3 print(a)4 #结果:{1, 2, 3, 66, 8, 9}
总结:推导式有,列表推导式,字典推导式,集合推导式,切记切记!!!元组是没有推导式的
生成器表达式:(结果 for 变量量 in 可迭代对象 if 条件筛选)
生成器表达式可以直接获取到生成器对象,生成器对象可以直接进行for循环,生成器具有惰性机制!!!
2019年11月13日