1.生成器(generator)
生成器的本质就是迭代器
1)生产器的三种生成方法
①通过生成器函数
②通过生成器表达式创建生成器
③通过数据转换
2.生成器函数
1)函数中包含了关键字yield,当前这个函数就不再是普通的函数了,而是一个生成器函数;此执行这个函数(即调用),只会获取到生成器,而不是去执行这个函数
def func(): print("九尾妖狐") yield "阿狸" #retuen换成了yield,表示次函数是一个生成器函数 func() #不再是执行函数,而是通过func()来创建一个生成器 print(func()) 输出: <generator object func at 0x000001A3D0380AF0>
#生成器的本质是迭代器,所以可以以迭代器的方式使用生成器
def func(): print("九尾妖狐") yield "阿狸" #retuen换成了yield,表示次函数是一个生成器函数 g = func() #不再是执行函数,而是通过func()来创建一个生成器 print(g.__next__()) 输出: 九尾妖狐 阿狸
2)return是直接返回函数的结果,结束函数的调用;yield也是返回结果,但会继续往下执行,可以让函数分段执行
def func(): print("九尾妖狐") yield "阿狸" #retuen换成了yield,表示次函数是一个生成器函数 print("远古巫灵") yield "泽拉斯" print("无双剑姬") yield "菲奥娜" g = func() #不再是执行函数,而是通过func()来创建一个生成器 print(g.__next__()) print(g.__next__()) print(g.__next__()) 输出: 九尾妖狐 阿狸 远古巫灵 泽拉斯 无双剑姬 菲奥娜
#注:生成器函数中,最后一个yield后面的内容,会被执行到,但是会报错(StopIteration),所以在最后一个yield之后,是不写代码的(最后一个yield后,再进行__next__()会报错)
3.send方法
1)__next__()方法和send()方法的共同点和区别
①共同点:__next__()可以让生成器向下执行一次;send()也可以让生成器向下执行一次
def func(): print("九尾妖狐") yield "阿狸" #retuen换成了yield,表示次函数是一个生成器函数 print("远古巫灵") yield "泽拉斯" print("无双剑姬") yield "菲奥娜" g = func() #不再是执行函数,而是通过func()来创建一个生成器 print(g.__next__()) print(g.send(1)) print(g.__next__()) 输出: 九尾妖狐 阿狸 远古巫灵 泽拉斯 无双剑姬 菲奥娜
②区别:send()该可以给上一个yield传一个值;但是不能给最后一个yield发送值,否则会报错,在第一次执行生成器的时候,只能使用__next__(),不能使用send(), 因为此时没有上一个yield
def func(): print("九尾妖狐") #黄色区域表示第一个__next__()的执行 a = yield "阿狸" #send传入的值赋值给了a print(a) #a的值由send传入 print("远古巫灵") b = yield "泽拉斯" #蓝色区域为send()的执行 print(b) print("无双剑姬") c = yield "菲奥娜" #灰色区域为下一个send()执行 g = func() #不再是执行函数,而是通过func()来创建一个生成器 print(g.__next__()) print(g.send(666)) print(g.send(999)) 输出: 九尾妖狐 阿狸 666 远古巫灵 泽拉斯 999 无双剑姬 菲奥娜
例:将生成器转换对象转化为一个列表
def func(): yield 11 yield 12 yield 13 yield 44 g = func() lst = list(g) print(lst) 输出: [11, 12, 13, 44]
4.推倒式
1)引入:生成一个列表,里面装1-14的数据
lst = [] for i in range(1,15): lst.append("python%s" % i) print(lst) 输出: ['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']
2)列表推导式完成上述要求
①语法
[最终结果(变量) for 变量 in 可迭代对象]
②完成上述要求
lst = ["python%s" % i for i in range(1,15)] print(lst) 输出: ['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']
③纯数字
lst = [ i for i in range(1,15)] print(lst) 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
④练习:
#获取1-100内能被3整数的数
lst = [i for i in range(1,101) 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, 100]
#获取100以内能被3整除的数的平方
lst = [i*i for i in range(1,101) if i%3==0] print(lst) 输出: [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]
#寻找名字中带有两个e的名字
names = [['Tom', 'Billy', 'Jefferson' , 'Andrew' , 'Wesley' , 'Steven' , 'Joe'],['Alice', 'Jill' , 'Ana', 'Wendy', 'Jennifer', 'Sherry' , 'Eva']] lst = [name for first in names for name in first if name.count("e")==2] print(lst) 输出: ['Jefferson', 'Wesley', 'Steven', 'Jennifer']
总结:其他的东西正常写,只是把最终的结果提到了前面
5.生成器表达式
1)生成器表达式和列表推导式的语法基本一昂,只是把[]换成了();这时候产生的就不再是一个列表,而是一个生成器
g = (i for i in range(1,10)) print(g) #g为生成器对象,就生成器表达式生成 print(g.__next__()) print(list(g) 输出: <generator object <genexpr> at 0x00000168E5FA0D00> 1 [2, 3, 4, 5, 6, 7, 8, 9]
#循环输出整个生成器
g = (i for i in range(1,10)) for el in g: print(el) 1 。 。 9
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] [] []
6.字典推导式
#将字典中的key和value互换
dic = {'a':"张三",'b':"李四"} dic_new = {dic[key]:key for key in dic} print(dic_new) 输出: {'张三': 'a', '李四': 'b'}
#将lst1列表中的值作为key;lst2列表中的值作为value,生成一个字典
lst1 = ["LOL","CF","DNF","qqfeiche"] lst2 = ["英雄联盟","穿越火线","地下城与勇士","QQ飞车"] dic = {lst1[i]:lst2[i] for i in range(len(lst1))} print(dic) 输出: {'CF': '穿越火线', 'LOL': '英雄联盟', 'qqfeiche': 'QQ飞车', 'DNF': '地下城与勇士'}
7.集合推导式
集合推导式可以直接生成一个集合;集合的特点的是无序,不重复;所以集合推导式自带去重功能
lst = ["九尾妖狐","远古巫灵","九尾妖狐","惩戒之箭"] s = {i for i in lst} #集合推导式 print(s) 输出: {'惩戒之箭', '远古巫灵', '九尾妖狐'}
总结:推导式有列表推导式、字典推导式、集合推导式,但是没有元组推导式
生成器表达式:(结果 for 变量 in 可迭代对象 if 条件筛选)
生成器表达式可以直接获取到生成器对象,生成器对象可以直接进行for许纳湖按,生成器具有惰性机制
例:
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) # g = (add(n, i) for i in add(n, i) for i in g) # g = (add(n, i) for i in add(n, i) for i in test()) # g = (add(n, i) for i in add(n, i) for i in [0,1,2,3]) # g = (add(10, i) for i in add(10, i) for i in [0,1,2,3]) # g = (add(10, i) for i [10,11,12,13]) print(list(g)) 输出: [20, 21, 22, 23]
8.练习
1)用推导式完成:过滤掉长度小于3的字符串列表,并将剩下的转化成大写字母
lst = ["apple","bababa","dog","pig","orange"] lst_new = [el.upper() for el in lst if len(el) > 3 ] print(lst_new) 输出: ['APPLE', 'BABABA', 'ORANGE']
2)推导式完成:求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元组列表
lst = [(x,y) for x in range(5) if x%2==0 for y in range(5) if y%2==1] print(lst) 输出: [(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]
3)推导式完成:求M中3,6,9组成的列表M=[[1,2,3],[4,5,6].[7,8,9]]
M=[[1,2,3],[4,5,6],[7,8,9]] lst = [i[2] for i in M] print(lst) 输出: [3, 6, 9]
#倒着推导
M = [3, 6, 9] lst = [[i-2,i-1,i] for i in M] print(lst) [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
4)推导式:求出50以内能被3整除的数的平方,并放入到一个列表中
lst = [i*i for i in range(50) if i%3==0] print(lst) 输出: [0, 9, 36, 81, 144, 225, 324, 441, 576, 729, 900, 1089, 1296, 1521, 1764, 2025, 2304]
5)推导式构建一个列表[0,2,4,6,8,10,12,14,16,18]
lst = [i for i in range(0,20,2)] print(lst) 输出: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]