暂停协程并返回呼叫者

时间:2017-01-26 10:07:39

标签: python python-3.5

短篇小说:

yield不能在async def函数中用于暂停执行并返回给调用者。在Python 3.5中有不同的方法吗?

修改 Scripted mongo的答案建议使用Python 3.6或将异步生成器定义为类。 Unfortunatley,前者不是一个选择。生成器可以工作,但为此目的定义一个类似乎比我自己的尝试更笨重。

据推测,没有简洁明了的解决方案?

长篇故事:

我需要编写可以暂停其操作,返回其调用者并在稍后停止的位置继续执行的函数。这些可以作为状态机实现,可能使用类,这些类会撕掉相关代码并且通常是不可读的。使用生成器,Python提供了一种或多或少的优雅方式来编写这样的函数:

def a():
    print('A Part 1')
    yield  # suspend execution to caller
    print('A Part 2')

def run(func):
    o = func()
    try:
        while True:
            print('running...')
            o.send(None)
    except StopIteration:
        pass    

run(a)
# running...
# A Part 1
# running...
# A Part 2

Python 3.3添加了yield from语法,它允许很好地嵌套这些函数。 yield from不是将执行返回给调用者,而是将执行转移到另一个函数:

def b():
    print('B Part 1')
    yield from a()
    print('B Part 2')

run(b)
# running...
# B Part 1
# A Part 1
# running...
# A Part 2
# B Part 2

Python 3.5引入了async defawait来区分协同程序和协同程序。当然我宁愿使用这些原生协同程序。只需将b替换为def,将async def替换为yield from,即可轻松重写await。但是,我没有找到一个规范的方法来暂停协程并返回给调用者。异步函数中不允许yield,等待只运行另一个函数。我想出了这个尴尬的解决方案:

import asyncio

@asyncio.coroutine
def awkward_suspend():
    yield

async def c():
    print('C Part 1')
    #yield  # SyntaxError: 'yield' inside async function 
    #await  # Syntax Error: invalid syntax
    await awkward_suspend()
    print('C Part 2')    

run(c)
# running...
# C Part 1
# running...
# C Part 2

此方法将yield包装在普通函数中,从而创建生成器,并将生成器标记为协程,因此可以await编辑。 这感觉非常像滥用语言。有没有办法在没有asyncio和尴尬的暂停函数的情况下实现相同的结果?

1 个答案:

答案 0 :(得分:1)

您可以改为使用sleep(0):

async def c():
    print('C Part 1')
    await asyncio.sleep(0)
    print('C Part 2')

sleep(0)恰好完成了awkward_suspend-简单的输出 实际上,它们在其中具有该yield语句的私有__sleep0()函数。