Python @asyncio.coroutine与async def

Python @asyncio.coroutine与async def,python,python-3.x,async-await,python-3.5,python-asyncio,Python,Python 3.x,Async Await,Python 3.5,Python Asyncio,使用我看到的asyncio库 @asyncio.coroutine def function(): ... 及 可以互换使用 这两者之间有什么功能上的区别吗?async def是Python 3.5中的一种新语法。 您可以在async defs中使用wait、async with和async for @coroutine是对async def的功能模拟,但它在Python 3.4+中工作,并利用了构造的收益,而不是等待 从实用角度来看,如果您的Python是3.5+,请不要使用@cor

使用我看到的
asyncio

@asyncio.coroutine
def function():
    ...

可以互换使用


这两者之间有什么功能上的区别吗?

async def是Python 3.5中的一种新语法。 您可以在
async def
s中使用
wait
async with
async for

@coroutine
是对
async def
的功能模拟,但它在Python 3.4+中工作,并利用了
构造的
收益,而不是
等待

从实用角度来看,如果您的Python是3.5+,请不要使用
@coroutine

从Python 3.5
开始,coroutine
正式成为一种独特的类型,因此
异步def
语法以及
wait
语句


在此之前,Python3.4通过将常规函数包装到
生成器中创建了协同路由,因此使用了decorator语法,而更像生成器的
则从
中产生

是的,使用
async def
语法的本机协同路由与使用
asyncio.coroutine
装饰器的基于生成器的协同路由在功能上存在差异

根据,它引入了
async def
语法:

  • 本机协同程序对象不实现
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    方法。因此,它们不能被迭代或传递 到
    iter()
    list()
    tuple()
    和其他内置程序。他们也 不能在<代码>循环中为..使用

    试图在本机协同程序上使用
    \uuuuu iter\uuuu
    \uuuu next\uuuu
    对象将导致类型错误

  • 普通生成器不能从
  • 本机协同程序中
    生成:这样做
    将导致类型错误

  • 基于生成器的协同程序(对于异步IO代码,必须使用
    @asyncio.coroutine
    )可以
    本机coroutine对象中产生

  • inspect.isgenerator()
    inspect.isgeneratorfunction()
    返回本机协同路由对象和本机协同路由函数的
    False

  • 上面的第1点意味着,虽然使用
    @asyncio.coroutine
    decorator语法定义的协程函数可以像传统的生成器函数一样工作,但使用
    async def
    语法定义的协程函数却不能

    下面是两个最小的、表面上等价的协同程序函数,它们由两个语法定义:

    import asyncio
    
    @asyncio.coroutine
    def decorated(x):
        yield from x 
    
    async def native(x):
        await x 
    
    尽管这两个函数的字节码几乎相同:

    >>> import dis
    >>> dis.dis(decorated)
      5           0 LOAD_FAST                0 (x)
                  3 GET_YIELD_FROM_ITER
                  4 LOAD_CONST               0 (None)
                  7 YIELD_FROM
                  8 POP_TOP
                  9 LOAD_CONST               0 (None)
                 12 RETURN_VALUE
    >>> dis.dis(native)
      8           0 LOAD_FAST                0 (x)
                  3 GET_AWAITABLE
                  4 LOAD_CONST               0 (None)
                  7 YIELD_FROM
                  8 POP_TOP
                  9 LOAD_CONST               0 (None)
                 12 RETURN_VALUE
    
    。。。唯一的区别是
    GET\u YIELD\u FROM\u ITER
    vs
    GET\u waitiable
    ,当尝试迭代返回的对象时,它们的行为完全不同:

    >>> list(decorated('foo'))
    ['f', 'o', 'o']
    

    列表(本机('foo')) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 TypeError:“协同程序”对象不可编辑
    显然,
    'foo'
    不是一个可以等待的对象,因此尝试用它调用
    native()
    没有多大意义,但希望重点是它返回的
    coroutine
    对象无论其参数如何都是不可iterable的


    Brett Cannon对
    异步
    /
    等待
    语法进行了更详细的研究:更深入地讨论了这一差异。

    最好了解3.5+中“从不使用@coroutine”的确切原因。这是一个真正的原因还是一个观点/经验法则?例如,我在3.4继承的代码库中有一些@coroutine装饰器,但所有新的开发都在3.5中。我是否应该将这些修饰符转换为
    async def
    ?要暂停协同程序执行,必须
    产生
    。但是不允许从本机协同程序内部生成
    yield
    !因此,即使在Python3.5+版本中,似乎仍然需要使用
    @coroutine
    。只需使用
    等待异步。sleep(0)
    @hmijail
    @coroutine
    标记的生成器可以等待,但如果可能,最好将它们转换为
    异步def
    等待异步。sleep(10)
    工作得很好。此外,我已经在asyncio master中将
    asyncio.sleep()
    转换为
    async def
    (将作为Python 3.7的一部分发布)。谢谢!但是为什么对本机协程函数执行
    inspect.iscoroutinefunction()
    return
    False
    >>> list(decorated('foo'))
    ['f', 'o', 'o']
    
    >>> list(native('foo'))
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'coroutine' object is not iterable