生成器和生成器表达式
# 生成器本质就是迭代器 # 第一种方法通过函数来获取生成器 def fun1(): print('111') yield '222' print('333') yield '444' g = fun1() # 函数不会执行而是获取生成器 print(g) # fun1是生成器函数,而g就是生成器 <generator object fun1 at 0x000001D1E2F1B3C8> print(g.__next__()) print(g.__next__()) # 当执行nextAPI的时候函数才会执行,yield是返回值 # yield和return都是来返回值区别是什么?yield是分段执行函数而return是直接停止函数
# 函数生成器可以使用send方法传值 def fun2(): a = yield '222' print('a=',a) b = yield '444' print('b=',b) yield '666' g = fun2() print(g.__next__()) print(g.send('首次传值')) print(g.send('二次传值')) # 222 # a= 首次传值 # 444 # b= 二次传值 # 666 # 打印结果,send同样是执行下一段代码,这里next执行的时候,代码到yield '222'停止运行 # yield返回值并且终止一段代码,到send执行a = 赋值
# 列表推导式 lst = ['三年级%s班' %i for i in range(1,8)] # print(lst) # ['三年级1班', '三年级2班', '三年级3班', '三年级4班', '三年级5班', '三年级6班', '三年级7班'] # 相当于 lst = [] for i in range(1,8): lst.append('三年级%s班' %(i)) print(lst) # 生成器推导式 gen = ('返回值是%s' %(i) for i in range(1,15) if i % 3 == 0) # 在推导式中可以用if进行筛选 # 相当于 def fun3(): for i in range(1,15): if i %3 == 0: yield '返回值是%s' %(i) gen1 = fun3() print(list(gen)) print(list(gen1)) # ['返回值是3', '返回值是6', '返回值是9', '返回值是12'] # 我们将生成器变成列表后的结果,两次结果相同 # 生成器只有在要值的时候才会取值,且生成器的next指针只能向下取值,也就是只能取一次值 def fun4(): print(111) yield 222 g = fun4() g1 = (i for i in g) g2 = (i for i in g1) print(list(g)) print(list(g1)) print(list(g2)) # 111 # [222] # [] # [] # 打印的结果,因为fun4是生成器函数,只有在取值的时候才会执行,list(g),将生成器转换为列表,这时候需要取值 # 所以执行了生成器函数,并且将返回值222取出,这时候生成器中就没有值了,也就是next指针无法向下继续走了,所以g2,g3都是空 # 字典推导式 dic = {i - 1:i for i in [1,2,3,4,5,6] if i %2 == 0} print(dic) # 集合推导式 lst = [1,2,3,4,5,5,6,6] s = {i for i in lst} print(s) # 集合推导式,去重
def add(a,b): return a + b def test(): for r in range(4): yield r g = test() for n in [2,5]: g = (add(n , i) for i in g) print(list(g)) #结果 [10, 11, 12, 13] # 首先在利用生成器函数获得一个生成器 # 这个时候执行循环,我们知道生成器的惰性机制,只有在next和send的取值时候才会执行 # 所以这时候for循环执行的时候生成器不会执行 # 这个时候我们debug一下 # test() = <generator object test at 0x000001C8142DDEC8> # 当循环执行完一遍后我们发现生成器的内存地址发生了变化<generator object <genexpr> at 0x000001C814A57448> # 因为生成器表达式的惰性机制他没有取值操作,但却进行了表达式的置换简单来说当循环结束后表达式 g = (add(n , i) for i in (add(n ,i) for i in test())) # 生成器没有取值,但却会不停的嵌套,当你运行next的时候才会进行取值,循环结束后n = 5 # print(g.__next__()) result:10,这个地方for循环是个烟雾弹,在执行for循环的时候生成器不停的嵌套但却不会真正运算或者取值 # 这也是生成器性能高的地方