使用Python创建生成器

发表时间: 2022-03-27 11:05

迭代器的好处是可以节省内存,如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器。

python中提供的生成器

1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行

2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表

生成器Generator:

本质:迭代器(所以自带了__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() 和 send()

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()的返回值

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"""