Python 生成器和减少

Python generators and reduce

我正在开发一个 Python3 tornado Web 服务器,它使用 @gen.coroutine 装饰器为 GET 请求提供异步协程。我想使用库中的这个函数:

@gen.coroutine
def foo(x):
    yield do_something(x)

这很简单:

@gen.coroutine
def get(self):
    x = self.some_parameter
    yield response(foo(x))

现在假设有多个相同类型的函数foo1foo2等。我想做一些类似 ...foo3(foo2(foo1(x).result()).result())...yield 的事情,而不仅仅是 get 方法中的 response(foo(x))

我认为使用 reduceresult 方法会很容易。但是,由于 tornado 的工作方式,我无法使用 result 方法将 foo 强制为 return。这意味着 yield reduce(...) 给出了一个错误:"DummyFuture does not support blocking for results"。从 SO 和其他地方的其他答案中,我知道我将不得不使用 IOLoop 或其他我不太理解的东西,并且...

...我的问题是,我怎样才能 避免评估 all foosyield 来自 get 方法的未计算块?

Edit:这不是 的副本,因为我想:1. 嵌套很多函数和 2. 尝试 not 立即评估。

在 Tornado 中,您必须 yield 协程中的 Future 才能获得结果。评论 Tornado's coroutine guide.

您可以编写一个作为协程的减速器。它运行每个协程以获得 Future,调用 yield 与 Future 以获得结果,然后在该结果上运行下一个协程:

from tornado.ioloop import IOLoop
from tornado import gen


@gen.coroutine
def f(x):
    # Just to prove we're really a coroutine.
    yield gen.sleep(1)
    return x * 2


@gen.coroutine
def g(x):
    return x + 1


@gen.coroutine
def h():
    return 10


@gen.coroutine
def coreduce(*funcs):
    # Start by calling last function in list.
    result = yield funcs[-1]()

    # Call remaining functions.
    for func in reversed(funcs[:-1]):
        result = yield func(result)

    return result


# Wrap in lambda to satisfy your requirement, to 
# NOT evaluate immediately.
latent_result = lambda: coreduce(f, g, h)
final_result = IOLoop.current().run_sync(latent_result)
print(final_result)