我想知道在Python 3中编写协同程序的最佳实践是什么.我正在开发基本方法,它应该接受一些输入(使用.send()方法),对此输入执行计算,然后产生输出.
我发现的第一种方法基本上是做以下事情:
def coroutine(func): data = yield while 1: data = yield func(data)
这似乎有效,但循环中的界限让我大吃一惊.它似乎首先产生一个函数,然后在恢复后接受输入并执行赋值.这对我来说完全不直观.
我正在看的另一种方法是:
def coroutine(): while 1: data = yield [ do stuff with data here ... ] yield result
这段代码对我来说更容易理解,它还允许我将代码放入生成器而不是传入函数.但使用起来很烦人.每次对生成器的实际调用(如"gen.send(2)")都必须跟随"gen.send(None)"以使生成器前进到下一个yield.
在我看来,这里的问题源于"yield"关键字用于两个不同的东西:return语句和输入语句.
如果可能,我想一个办法,让我带输入,该输入做计算,然后产生输出,而不必在功能传递和使用的俏皮话作为第一种方法,或无需发送多余的值作为第二做法.我怎样才能做到这一点?
请注意:实际上,我将发送多个值.所以有无关的"g.send(无)"陈述的问题变得更糟.
您可以像在第一个示例中那样执行此操作.你只需要在循环中"对数据进行处理".这是一个例子:
def coroutine(): data = yield while True: print("I am doing stuff with data now") data = data * 2 data = yield data
你可以像这样使用它:
>>> co = coroutine() >>> next(co) >>> co.send(1) I am doing stuff with data now 2 >>> co.send(88) I am doing stuff with data now 176
你是正确的,yield
扮演双重角色,既产生结果又接受随后传入的值send
.(同样,send
扮演一个双重和互补的角色,因为每个send
调用都返回生成器产生的值.)注意那里的顺序:当你有一个yield
表达式时,它首先产生值out,然后yield
表达式的值变为任何值是sent
在事后.
这可能看起来"倒退",但你可以通过循环来做它"转发",就像你基本上已经做过的那样.这个想法是你首先产生一些初始值(也许是无意义的).这是必要的,因为send
在产生值之前不能使用(因为没有yield
表达式来评估发送的值).然后,每次使用时yield
,您都会发出"当前"值,同时接受用于计算"下一个"值的输入.
正如我在评论中提到的,从你的例子中不清楚你为什么要使用发电机.在许多情况下,只需编写一个具有自己的方法来传递和解决问题的类就可以实现类似的效果,如果你编写了类,你可以随意创建API.如果您选择使用发电机,你必须接受双重输入/输出角色send
和yield
.如果你不喜欢它,不要使用生成器(或者,如果你需要它们提供的暂停函数状态,你可以使用它们,但用一个将发送和屈服分开的类包装它们).