python学习(生成器,生成推导式)
Posted 唯你如我心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python学习(生成器,生成推导式)相关的知识,希望对你有一定的参考价值。
一. 生成器
生成器的实质就是迭代器, 在python中有三种方式获得生成器
1. 生成器函数
2. 各种推导式实现生成器
3. 数据转换也可以获得生成器
def func(): print("111") return 222 ret = func() print(ret) #结果: # 111 # 222
将函数中的return 换成 yield就是生成器
def func(): print("111") yield 222 ret = func() print(ret) #结果: #<generator object func at 0x0000025256283A40>
以上两段代码执行的结果不一样. 因为下面的代码有yield,所以真个函数就是一个生成器函数.这个时候再执行这个函数,就不在是函数的执行了.而是获取这个生成器.
所以要想运行这个函数,就要执行__next__()函数来执行函数
def func(): print("111") yield 222 gener = func() # 这个时候函数不会执行. 而是获取到?生成器 ret = gener.__next__() # 这个时候函数才会执行. yield的作?和return?样. 也是返回数据 print(ret) #结果: # 111 # 222
可以看到:return和yield执行的效果是一样. 但是二者是有区别的,yield是分段执行一个函数,return是直接停止执行函数
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 #222 #333 #444 #Traceback (most recent call last): # File "D:/pycharm项目/week3/day3/函数生成器.py", line 103, in #<module> # ret3 = gener.__next__() # 最后?一个yield执?行行完毕. 再次#__next__()程序报错, 也就是 说. 和return?无关了了. #StopIteration
当程序运行完后?个yield. 那么后面继续进行__next__()程序会报错.
生成器作用:
def cloth(): lst = [] for i in range(0, 100): lst.append("衣服"+str(i)) return lst cl = cloth() print(cl) #结果: #[‘衣服0‘, ‘衣服1‘, ‘衣服2‘, ‘衣服3‘, ‘衣服4‘, ‘衣服5‘, ‘衣服6‘, ‘衣服7‘, ‘衣服8‘, ‘衣服9‘, ‘衣服10‘, ‘衣服11‘, ‘衣服12‘, ‘衣服13‘, ‘衣服14‘, ‘衣服15‘, ‘衣服16‘, ‘衣服17‘, ‘衣服18‘, ‘衣服19‘, ‘衣服20‘, ‘衣服21‘, ‘衣服22‘, ‘衣服23‘, ‘衣服24‘, ‘衣服25‘, ‘衣服26‘, ‘衣服27‘, ‘衣服28‘, ‘衣服29‘, ‘衣服30‘, ‘衣服31‘, ‘衣服32‘, ‘衣服33‘, ‘衣服34‘, ‘衣服35‘, ‘衣服36‘, ‘衣服37‘, ‘衣服38‘, ‘衣服39‘, ‘衣服40‘, ‘衣服41‘, ‘衣服42‘, ‘衣服43‘, ‘衣服44‘, ‘衣服45‘, ‘衣服46‘, ‘衣服47‘, ‘衣服48‘, ‘衣服49‘, ‘衣服50‘, ‘衣服51‘, ‘衣服52‘, ‘衣服53‘, ‘衣服54‘, ‘衣服55‘, ‘衣服56‘, ‘衣服57‘, ‘衣服58‘, ‘衣服59‘, ‘衣服60‘, ‘衣服61‘, ‘衣服62‘, ‘衣服63‘, ‘衣服64‘, ‘衣服65‘, ‘衣服66‘, ‘衣服67‘, ‘衣服68‘, ‘衣服69‘, ‘衣服70‘, ‘衣服71‘, ‘衣服72‘, ‘衣服73‘, ‘衣服74‘, ‘衣服75‘, ‘衣服76‘, ‘衣服77‘, ‘衣服78‘, ‘衣服79‘, ‘衣服80‘, ‘衣服81‘, ‘衣服82‘, ‘衣服83‘, ‘衣服84‘, ‘衣服85‘, ‘衣服86‘, ‘衣服87‘, ‘衣服88‘, ‘衣服89‘, ‘衣服90‘, ‘衣服91‘, ‘衣服92‘, ‘衣服93‘, ‘衣服94‘, ‘衣服95‘, ‘衣服96‘, ‘衣服97‘, ‘衣服98‘, ‘衣服99‘] def cloth(): for i in range(0, 10000): yield "?衣服"+str(i) cl = cloth() print(cl.__next__()) print(cl.__next__()) print(cl.__next__()) print(cl.__next__()) #结果: # ?衣服0 # ?衣服1 # ?衣服2 # ?衣服3
区别: 第一种是将循环的内容直接全部拿出来,很占用内存. 第二种使用生成器,一个__next__函数只拿出一个,之后循环停止在当前位置,下一个再取值再从停止位置继续向前取值.
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
二. 列表推导式
列表推导式:最终给的是列表
语法: [最终结果(变量) for 变量 in 可迭代对象]
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‘] 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‘]
列表推导式是通过?行来构建你要的列表, 列表推导式看起来代码简单. 但是出现错误之后很难排查.
?生成器表达式和列表推导式的语法基本上是?样的. 只是把[]替换成()
g = (i for i in range(10)) print(g) #打印结果是一个生成器 #结果: #<generator object <genexpr> at 0x0000029147073A40> gen = ("麻xx我第%s次爱你" % i for i in range(10)) for i in gen: #遍历生成器内容 print(i) #结果: #麻xx我第0次爱你 #麻xx我第1次爱你 #麻xx我第2次爱你 #麻xx我第3次爱你 #麻xx我第4次爱你 #麻xx我第5次爱你 #麻xx我第6次爱你 #麻xx我第7次爱你 #麻xx我第8次爱你 #麻xx我第9次爱你
生成器表达式可以进行筛选:
lst = [i for i in range(1,101) if i % 3 == 0] print(lst) #结果: #[3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 93, 96, 99] lst = [i*i for i in range(1,100) 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 = [ii for i in names for ii in i if ii.count(‘e‘) ==2] print(lst) #结果: #[‘Jefferson‘, ‘Wesley‘, ‘Steven‘, ‘Jennifer‘]
?生成器表达式和列列表推导式的区别:
1. 列表推导式比较耗内存. ?次性加载. 生成器表达式几乎不占?用内存. 使用的时候才分配和使用内存
2. 得到的值不?样. 列表推导式得到的是?个列列表. 生成器表达式获取的是?个生成器.
生成器的惰性机制:生成器只有在访问的时候才取值. 说白了就是找他要他才给值,不要的话,他是不会执行的
总结:
推导式有列表推导式,字典推导式,集合推导式,没有元组推导式
生成器表达式:(结果 for 变量 in 可迭代对象 if 条件筛选)
生成器表达式可以直接获取到生成器对象,生成器可以直接进行for循环. 生成器具有惰性机制
以上是关于python学习(生成器,生成推导式)的主要内容,如果未能解决你的问题,请参考以下文章
python学习第十四天 生成器函数进阶 生成器表达式 各种推导式