【问题标题】:Python generators and reducePython 生成器和减少
【发布时间】:2017-01-04 02:50:30
【问题描述】:

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

@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 的工作方式,我无法强制foos 使用result 方法返回某些内容。这意味着yield reduce(...) 给出错误:“DummyFuture 不支持结果阻塞”。从 SO 和其他地方的其他答案中,我知道我将不得不使用 IOLoop 或其他我不太了解的东西,并且...

...我的问题是,我如何避免从 get 方法评估 all foosyield 未评估的块?

编辑:这不是this question 的重复,因为我想:1. 嵌套很多函数,2. 尝试 not 立即评估。

【问题讨论】:

标签: python python-3.x generator tornado


【解决方案1】:

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

你可以写一个协程的reducer。它运行每个协程以获取 Future,使用 Future 调用 yield 以获取结果,然后在该结果上运行下一个协程:

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)

【讨论】:

  • 谢谢,这是有道理的。您能否解释一下在 coreduce 函数中使用多个 yield 和 return 语句时发生了什么?
  • 每个“yield”都等待被调用的协程完成,并将它返回的 Future 解析为结果。 “return”语句从协程返回一个值。协程返回的任何内容都将成为其 Future 的值。
  • “协程返回的任何东西都将成为其 Future 的值。”:这是迄今为止我听到的关于协程的最有用的说法。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 2011-07-15
  • 2015-11-01
  • 2016-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多