迭代器的好处是可以节省内存,如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
特点:惰性运算,开发者自定义
一个包含yield关键字的函数就是一个生成器函数。yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值,而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
import timedef genrator_fun1(): a = 1 print('现在定义了a变量') yield a b = 2 print('现在又定义了b变量') yield bg1 = genrator_fun1() # 不执行函数 得到一个生成器对象print('g1 : ', g1) # 打印g1可以发现g1就是一个生成器 注意这里并没有执行函数print('-' * 20) # 我是华丽的分割线print(next(g1))time.sleep(1) # sleep一秒看清执行过程print(next(g1))"""g1 : <generator object genrator_fun1 at 0x7fb5aae851d0>--------------------现在定义了a变量1现在又定义了b变量2"""
生成器有什么好处呢?就是不会一下子在内存中生成太多数据
假如我想让工厂给学生做校服,生产2000000件衣服,我和工厂一说,工厂应该是先答应下来,然后再去生产,我可以一件一件的要,也可以根据学生一批一批的找工厂拿。
而不能是一说要生产2000000件衣服,工厂就先去做生产2000000件衣服,等回来做好了,学生都毕业了。。。
def produce(): """生产衣服""" for i in range(2000000): yield "生产了第%s件衣服" % iproduct_g = produce()print(product_g.__next__()) # 要一件衣服print(product_g.__next__()) # 再要一件衣服print(product_g.__next__()) # 再要一件衣服print("----------------分割线---------------------")num = 0for i in product_g: # 要一批衣服,比如5件 print(i) num += 1 if num == 5: break"""生产了第0件衣服生产了第1件衣服生产了第2件衣服----------------分割线---------------------生产了第3件衣服生产了第4件衣服生产了第5件衣服生产了第6件衣服生产了第7件衣服"""# 到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。# 剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
读取文件
import timedef tail(filename): f = open(filename) f.seek(0, 2) #从文件末尾算起 while True: line = f.readline() # 读取文件中新的文本行 if not line: time.sleep(0.1) continue yield linetail_g = tail('tmp')for line in tail_g: print(line)
next()让包含yield的函数(Generator)执行
next()和send()在一定意义上作用是相似的,区别是send()可以传递值给yield表达式,而next()不能传递特定的值,只能传递None进去。因此,我们可以看做c.next() 和 c.send(None) 作用是一样的。
第一次调用时,请使用next()语句或是send(None),不能使用send发送一个非None的值,否则会出错的,因为没有yield语句来接收这个值。
def x(): print('bai wei') m = yield 5 print(m) d = yield 12 print('reach here ')c = x()next(c) # 启动generatornext(c) # 给yield表达式传一个None值 和 c.send(None) 等价"""bai weiNone"""
send 传值
def x(): print('bai wei') m = yield 5 # m的值就是send传的 hi print(m) d = yield 12 print('reach here ')c = x()next(c) # 启动generatorc.send("hi")"""bai weihi"""
第一次调用时 不能使用send传一个非None的值
def x(): print('bai wei') m = yield 5 print(m) d = yield 12 print('reach here ')c = x()c.send("hi") # 报错"""Traceback (most recent call last): File "xx.py", line 10, in <module> c.send("hi")TypeError: can't send non-None value to a just-started generator"""
send(msg) 和 next()是有返回值的,它们的返回值很特殊,返回的是下一个yield表达式的参数。比如yield 5,则返回 5
def h(): print('Wen Chuan') m = yield 5 # m的值就是send传过来的 Fighting! print(m) d = yield 12 print('We are together!')c = h() # 不执行函数 得到一个生成器m = next(c) # m 获取了yield 5 的参数值 5d = c.send('Fighting!') # d 获取了yield 12 的参数值12print('We will never forget the date', m, '.', d)"""Wen ChuanFighting!We will never forget the date 5 . 12"""