前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python的协程

python的协程

作者头像
哒呵呵
发布2018-08-06 15:00:05
3430
发布2018-08-06 15:00:05
举报
文章被收录于专栏:鸿的学习笔记鸿的学习笔记

yield指令有两个功能:yield item用于产出一个值,反馈给next()的调用方。

还可以作出让步,暂停执行生成器,让调用方继续工作,直到需要使用另一个值时再调用next()。

协程的yield语句写在表达式右边(func = yield),可以产出值,也可以不产出值,如果yield后面没有表达式,则生成器产出None。协程可能会从调用方接受数据,

这时使用的是send(data)。所以我们可以理解yield为一种流程控制工具,实现协作式多任务。

先简单看下协程:

https://www.python.org/dev/peps/pep-0342/,pep342详细介绍了协程的使用

在这篇文章里,

Coroutines are a natural way of expressing many algorithms, such as simulations, games, asynchronous I/O, and other forms of event-driven programming or co-operative multitasking.

指出了为啥要使用协程,其中重要的几点:

--Redefine yield to be an expression, rather than a statement.

--Add a new send() method for generator-iterators, which resumes the generator and sends a value that becomes the result of the current yield-expression.

--Add a new throw() method for generator-iterators, which raises an exception at the point where the generator was paused, and which returns the next value yielded by the generator, raising StopIteration if the generator exits without yielding another value.

--Add a close() method for generator-iterators, which raises GeneratorExit at the point where the generator was paused.

详细的可以继续看这篇Guido van Rossum, Phillip J. Eby联合执笔的文章。

看看示例吧!

def test():

print('-->协程开始')

x = yield

print('-->收到的信息',x)

写一个简单的函数,将参数传给a

a = test()

先来看看改造后的协程函数有什么特点吧。

dir(a)

Out[3]:

['__class__',

...

'close',

'send',

'throw']

如上文所述,多了三个方法。

现在看看怎么使用吧,

调用

next(a)

-->协程开始

此时数据还没开始到x = yield这里

a.send(32)

-->收到的信息 32

Traceback (most recent call last):

File "<ipython-input-9-bf16f08d219f>", line 1, in <module>

a.send(32)

StopIteration

你们会看出来,调用send方法后,x被赋值32,到了末尾发现生成器结束了,抛出StopIteration错误

调用next被称为"prime"协程(让协程向前执行到第一个yield表达式,准备好作为活跃的协程使用)

这里的x只有等到客户端的代码再激活协程时才会赋值。

我们再来高级一点的,之前文章写过求平均值的高阶函数

def avg():

total = 0.0

count = 0

average = None

while True:

temp = yield average

total += temp

count += 1

average = total/count

在这里,会先返回average,再执行下一个send时,才会计算temp和之后的数

a = avg()

next(a)

a.send(10)

Out[19]: 10.0

a.send(20)

Out[20]: 15.0

a.send(65)

Out[21]: 31.666666666666668

只有等到.close()才会停止

当然你会觉得每次写next烦,你可以使用一个装饰器,预先激活协程

那终止协程和异常处理呢?

可以使用传入异常的方式,关闭协程,例如:

a.send('ds')

Traceback (most recent call last):

File "<ipython-input-29-f2d905baf516>", line 1, in <module>

a.send('ds')

File "<ipython-input-16-2b438fb3c5cf>", line 7, in avg

total += temp

TypeError: unsupported operand type(s) for +=: 'float' and 'str'

这时候再去查看协程的状态:

inspect.getgeneratorstate(a)#这个可以查看各种函数的状态,具体请查阅官方文档

Out[30]: 'GEN_CLOSED'

显示已经关闭了。

你可以在代码里加上try/finally语句处理异常,但千万记得写好你会抓取的错误。

或者在不断循环加上某个变量,break掉

有个关于yield from的解释的文章,https://www.python.org/dev/peps/pep-0380/,大概提提里面的内容

第一个用途:可以简化

for v in g:

yield v

类似的语句

def test():

yield from 'da'

yield from [1,2,3]

得出的结果如下:

list(test())

Out[34]: ['d', 'a', 1, 2, 3]

核心的一句话在于

A syntax is proposed for a generator to delegate part of its operations to another generator.

这是两个迭代器的通道,把最外层的调用金额最内层的Subgenerator联系起来。

文中给出了应用:

--Any values that the iterator yields are passed directly to the caller.

--Any values sent to the delegating generator using send() are passed directly to the iterator. If the sent value is None, the iterator's __next__() method is called. If the sent value is not None, the iterator's send() method is called. If the call raises StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.

--Exceptions other than GeneratorExit thrown into the delegating generator are passed to the throw() method of the iterator. If the call raises StopIteration, the delegating generator is resumed. Any other exception is propagated to the delegating generator.

--If a GeneratorExit exception is thrown into the delegating generator, or the close() method of the delegating generator is called, then the close() method of the iterator is called if it has one. If this call results in an exception, it is propagated to the delegating generator. Otherwise, GeneratorExit is raised in the delegating generator.

--The value of the yield from expression is the first argument to the StopIteration exception raised by the iterator when it terminates.

--return expr in a generator causes StopIteration(expr) to be raised upon exit from the generator.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 鸿的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档