从Python中的协同程序中生成一个值,也称为convert callback to generator
我不熟悉Python和函数式编程。我使用的是2.7.6版 我正在使用Tornado框架进行异步网络请求。根据我对函数式编程的了解,我希望我的数据通过生成器在代码中流动。我已经使用生成器完成了我需要的大部分工作,并在数据流通过我的函数调用时转换数据 在流的最后,我想对一些数据发出REST请求。在我将数据提交给Tornado之前,我有一个for循环,用于启动pull,然后发送http请求。Tornado提供的http对象将回调函数作为一个选项,并始终返回一个Future——实际上是Tornado Future对象,而不是官方的Python Future 我的问题是,因为我现在使用生成器在代码中提取数据,所以我不想再使用回调函数。我的理由是,在我从回调中获取数据之后,我的数据现在被推送到我的代码中,我不能再使用生成器了 我的目标是创建一个如下所示的界面:从Python中的协同程序中生成一个值,也称为convert callback to generator,python,asynchronous,functional-programming,generator,tornado,Python,Asynchronous,Functional Programming,Generator,Tornado,我不熟悉Python和函数式编程。我使用的是2.7.6版 我正在使用Tornado框架进行异步网络请求。根据我对函数式编程的了解,我希望我的数据通过生成器在代码中流动。我已经使用生成器完成了我需要的大部分工作,并在数据流通过我的函数调用时转换数据 在流的最后,我想对一些数据发出REST请求。在我将数据提交给Tornado之前,我有一个for循环,用于启动pull,然后发送http请求。Tornado提供的http对象将回调函数作为一个选项,并始终返回一个Future——实际上是Tornado F
urls = (...generated urls...)
responses = fetch(urls)
其中响应是完整URL上的生成器
在许多事情中,我试图做的是将回调的结果转换成生成器。我曾经考虑过类似的事情,尽管我还远没有在其他问题上实现它,我将很快解释。但是,我希望我的fetch函数看起来像这样:
def fetch(urls):
def url_generator():
while True:
val = yield
yield val
@curry
def handler(gen, response):
gen.send(response)
gen = url_generator()
for u in urls:
http.fetch(u, callback=handler(gen))
return gen
我简化了代码和语法以关注问题,但我认为这会很好地工作。我的策略是定义一个协同程序/生成器,然后在收到响应时将其发送给它
我遇到的最大问题是协同程序/生成器。即使我用上面的方式定义了一个生成器并执行了下面的操作,我也会得到一个无限循环——这是我的主要问题之一
def gen():
while True:
val = yield
print 'val', val
yield val
print 'after', val
break
g = gen()
g.send(None)
g.send(10)
for e in g:
print e
这将在corroutine中按预期在10后打印val10,并使用中断,但for循环从未获得10的值。休息时它不会打印任何东西。如果我去掉断点,那么我得到无限循环:
val None
None
after None
None
val None
None
after None
None
...
如果我删除for循环,那么协同程序在等待第二个成品时将只打印val10
。我希望这样。然而,使用它不会产生任何效果
类似地,如果我删除for循环并将其替换为print next(g)
,那么我会得到一个StopIteration错误,我假设这意味着我在没有更多值的生成器上调用了next
无论如何,当我深入研究Python时,我完全不知所措。我认为这是Python中的常见情况,有人知道一种很好的方法。我搜索了“将回调转换为生成器”之类的东西,但运气不太好
另一方面,我可能会从http请求中产生每个未来,但我没有太多的运气“等待”未来完成。我读了很多关于“收益来自”的书,但它似乎是特定于Python 3的,Tornado似乎还不能在Python 3上工作
感谢您的观看,并感谢您提供的任何帮助。Tornado在Python 3上运行得非常好
上面的简化代码的问题在于,这并没有达到预期效果:
val = yield
您希望生成器在那里暂停(阻塞for循环),直到其他函数调用g.send(value)
,但实际情况并非如此。相反,代码的行为类似于:
val = yield None
因此for循环以最快的速度接收None
值。在收到每个None
后,它隐式调用g.next()
,这与g.send(None)
相同。因此,您的代码相当于:
def gen():
while True:
val = yield None
print 'val', val
yield val
print 'after', val
g = gen()
g.send(None)
g.send(10)
while True:
try:
e = g.send(None)
print e
except StopIteration:
break
阅读这个版本的代码,其中隐式行为是显式的,我希望能够清楚地知道为什么它只是在无限循环中生成None
您需要的是一个函数向队列的头部添加项目,而另一个函数阻止等待项目,并在项目准备就绪时将其从队列的尾部拉出。从龙卷风4.2开始,我们有:
web spider示例接近您想要做的,我相信您可以调整它:
好问题:)。写得好,研究得好,谢谢。这是我的第一个问题:)Tornado确实与Python3一起工作,是@curry
您的生成器吗?谢谢您的光临。我对py3上的Tornado有一些问题,但我会再次检查@curry来自PyMonad包。当我使用async generator时,我必须为特定函数预定义模式。也许你应该看看这个。我刚刚开始研究PyMonad,如果我有解决方案,我会告诉你的Jesse,非常感谢你的解释。一旦我的行为正常,我会将其标记为正确,并用有效的解决方案更新我的问题。有趣的是,在我执行此调用后,我计划将结果放入MongoDB。。。我打算用马达!事实上,我昨天在研究你的个人网站时偶然发现了它。小世界:)再次感谢你们的帮助。没问题,很高兴我能帮上一点忙。如果您还需要什么,请告诉我。