python菜鸟学习Day12(yield)

家住魔仙堡 提交于 2019-12-26 19:38:44

在python中,带yield的函数称为生成器(generator),python对协程的支持也是通过生成器实现的。
yield
首先将yield当成一个断点标记,中断,return 。当程序执行到yield处,返回yield后边的变量,中断。其他程序获取这个变量,调用生成器的next()函数,程序又回到生成器,接着向下执行。
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。


def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))

执行结果

starting...
4
********************
res: None
4

1首先foo函数含有yield,是一个生成器,g = foo(),并不执行foo()函数,而是返回一个迭代器对象赋值给g。
2 调用迭代器对象g的next()方法,foo函数开始执行,打印"starting…",进入while循环,执行到yield,中断,return后边的变量4,程序跳转回到print(next(g))。即print(yield返回的变量4)。
3 顺序执行print("*"*20)。
4 再次调用迭代器对象g的next()方法,程序跳转到上次next结束的地方,即res赋值操作,因为变量4被return出去了,所以res赋值为空。执行print(“res:”,res),即打印res: None,继续循环到yield,再次中断,return 后边的变量4,然后跳转到print(next(g)),即打印4。

生成器有一个重要的方法next(),调用next(),程序从上次next()停止的地方开始执行,直至遇到yield,返回后面的变量,此步停止。

send例子
send(value)
迭代器对象的send方法,发送一个值value给生成器,并返回下一个yield的值(也就行调用next()方法)。

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(g.send(7))

结果

starting...
4
********************
res: 7
4

最后一步:g.send(7),回到上次yield结束的地方,即res赋值操作,即把send的值7赋值给res,继续执行,即打印res,然后执行到yield,返回yield后面的变量4,中断跳出。回到print(g.send(7)),即打印pirnt(4).

使用生成器可以节省内存空间,比如for i in range(1000),则会生成一个list存储1000个元素,而for i in xrange(1000),xrange(1000)就是一个生成器,每次yield 一个元素。

读取文本,如果直接读取,会将文本内容全部加载到内存中,占用大量内存,而生成器则每次yield固定大小BLOCK_SIZE 的文本块到内存。

def read_file(fpath): 
    BLOCK_SIZE = 1024 
    with open(fpath, 'rb') as f: 
        while True: 
            block = f.read(BLOCK_SIZE) 
            if block: 
                yield block 
            else: 
                return

send函数和for循环都会自动调用next()函数。当函数执行结束时,generator 自动抛出 StopIteration 异常,表示迭代完成。在 for 循环里,无需处理 StopIteration 异常,循环会正常结束。

Python对协程的支持是通过generator实现的。
在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取由yield语句返回的下一个值。但是Python的yield不但可以返回一个值,它还可以接收调用者发出的参数。
生产者–消费者模型

def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None) #启动生成器 想当与next(c)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

1 c = consumer(),返回一个迭代器对象。并不执行consumer,在调用next方法才会执行。
2 produce(c )中,c.send(None) 启动生成器。produce一旦生产了东西,通过 c.send(n)切换到consumer,consumer通过yield拿到东西,经过处理后,有经过下一个yield返回。pruduce拿到处理的结果,继续生产下一个东西。produce决定不生产,通过c.close()关闭consumer,整个过程结束.

链接: https://blog.csdn.net/mieleizhi0522/article/details/82142856
链接: https://www.runoob.com/w3cnote/python-yield-used-analysis.html
链接: https://www.liaoxuefeng.com/wiki/1016959663602400/1017968846697824#0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!