分享

python生成器

 禁忌石 2022-03-28

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

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多