Python 生成器,协程

生成器generator

    生成器可以简单有效的创建庞大的可迭代对象,而不需要在直接在内存中创建存储整个序列

        可以使用生成器推导式或者生成器函数来创建生成器

        生成器函数返回数据时使用yield语句,而不是使用return

>>> def countdown(n):
...     print("Counting down from %d" %n)
...     while n>0:
...             yield n
...             n -=1
...     return 'done'
...
>>> c = countdown(10)    #c为一个生成器对象

   

    可以通过next()函数或者生成器对象的__next__()方法来获得生成器的下一个返回值

    当计算到最后一个元素后,没有更多的元素时,抛出StopInteration,生成器终止

>>> c = countdown(3)
>>> next(c)
Counting down from 3
3
>>> c.__next__()
2
>>> next(c)
1
>>> next(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: done

    通常直接通过for循环来迭代生成器,并且不需要关心StopInteration

    但是用for循环调用生成器时,发现拿不到生成器的return语句的返回值。

    如果想要拿到返回值,必须捕获StopInteration错误,返回值包含在StopInteration的value中

>>> while True:
...     try:
...         x = next(c)
...         print(c)
...     except StopIteration as e:
...         print('Generator return value:', e.value)
...         break
...

    当一个生成器没有全部迭代完成,但是不在使用了,可以调用close()方法关闭生成器,通常不必手动调用close()方法

c = countdown(10)
>>> next(c)
1
>>> c.close()
>>> next(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration


扫描二维码关注公众号,回复: 11401675 查看本文章

协程

         协程可以理解为就像生成器那样可以暂停的函数


    在函数内,当yield语句作为表达式使用,出现在赋值运算符的右边,在向函数发送值时函数将执行

    这种生成器函数可以被称为协程函数,而对协程函数的调用可以获得协程对象

"协程"一词可以用于协程函数和协程对象

>>> def coroutine():
...     print("Start Coroutine")
...     r = 'ok'
...     while True:
...             n = yield r
...             print('receiver %s' % n)
...
>>> c = coroutine()
>>> c.send(1)    
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't send non-None value to a just-started generator
>>> c.send(None)    #next(c)
Start Coroutine
'ok'
>>> c.send(1)
receiver 1
'ok'
>>> c.close()
>>> c.send(2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

        在发送数据之前,应该调用c.send(None)启动生成器或者使用next()函数,使协程执行第一个yield之前的语句

        启动后协程会挂起,等待协程对象c的send()方法发送值

        yield语句会接收send()发送的值,并返回yield 语句后的值

        协程一般会不断执行下去,可以通过close()方法关闭协程


我们可以使用asyncio模块中的@asyncio.coroutine装饰器来使协程函数在调用时自动运行到yield语句前,而不需要提前调用send(None)或next()函数

具体的asyncio模块和协程的讲解可以看另一篇文章


猜你喜欢

转载自blog.csdn.net/DAGU131/article/details/79355695