@asyncio.coroutine 与异步定义
@asyncio.coroutine vs async def
有了我见过的 asyncio
库,
@asyncio.coroutine
def function():
...
和
async def function():
...
可互换使用。
两者在功能上有什么区别吗?
async def
是 Python 3.5 的新语法。
您可以在 async def
内使用 await
、async with
和 async for
。
@coroutine
是 async def
的功能类似物,但它在 Python 3.4+ 中工作,并利用 yield from
构造而不是 await
.
如果您的 Python 是 3.5+,从实用的角度来看,永远不要使用 @coroutine
。
从 Python 3.5 coroutines
正式成为一个独特的类型,因此 async def
语法以及 await
语句.
在此之前,Python 3.4 通过将常规函数包装到 generators
中来创建协程,因此装饰器语法和更像生成器的 yield from
。
是的,使用 async def
语法的原生协程与使用 asyncio.coroutine
装饰器的基于生成器的协程之间存在功能差异。
根据 PEP 492,它引入了 async def
语法:
Native coroutine objects do not implement __iter__
and
__next__
methods. Therefore, they cannot be iterated over or passed
to iter()
, list()
, tuple()
and other built-ins. They also
cannot be used in a for..in
loop.
An attempt to use __iter__
or __next__
on a native coroutine
object will result in a TypeError .
Plain generators cannot yield from
native coroutines: doing so
will result in a TypeError .
generator-based coroutines (for asyncio code must be decorated with
@asyncio.coroutine
) can yield from
native coroutine objects.
inspect.isgenerator()
and inspect.isgeneratorfunction()
return False
for native coroutine objects and native coroutine functions.
上面的第 1 点意味着虽然使用 @asyncio.coroutine
装饰器语法定义的协程函数可以像传统的生成器函数一样运行,但使用 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_YIELD_FROM_ITER
与 GET_AWAITABLE
,当尝试遍历它们 return:
的对象时,它们的行为完全不同
>>> 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
显然 'foo'
不是可等待的,因此尝试用它调用 native()
没有多大意义,但希望很清楚 coroutine
反对它returns 不可迭代,无论其参数如何。
Brett Cannon 对 async
/await
语法的更详细研究:How the heck does async/await work in Python 3.5? 更深入地介绍了这种差异。
有了我见过的 asyncio
库,
@asyncio.coroutine
def function():
...
和
async def function():
...
可互换使用。
两者在功能上有什么区别吗?
async def
是 Python 3.5 的新语法。
您可以在 async def
内使用 await
、async with
和 async for
。
@coroutine
是 async def
的功能类似物,但它在 Python 3.4+ 中工作,并利用 yield from
构造而不是 await
.
如果您的 Python 是 3.5+,从实用的角度来看,永远不要使用 @coroutine
。
从 Python 3.5 coroutines
正式成为一个独特的类型,因此 async def
语法以及 await
语句.
在此之前,Python 3.4 通过将常规函数包装到 generators
中来创建协程,因此装饰器语法和更像生成器的 yield from
。
是的,使用 async def
语法的原生协程与使用 asyncio.coroutine
装饰器的基于生成器的协程之间存在功能差异。
根据 PEP 492,它引入了 async def
语法:
Native coroutine objects do not implement
__iter__
and__next__
methods. Therefore, they cannot be iterated over or passed toiter()
,list()
,tuple()
and other built-ins. They also cannot be used in afor..in
loop.An attempt to use
__iter__
or__next__
on a native coroutine object will result in a TypeError .Plain generators cannot
yield from
native coroutines: doing so will result in a TypeError .generator-based coroutines (for asyncio code must be decorated with
@asyncio.coroutine
) canyield from
native coroutine objects.
inspect.isgenerator()
andinspect.isgeneratorfunction()
returnFalse
for native coroutine objects and native coroutine functions.
上面的第 1 点意味着虽然使用 @asyncio.coroutine
装饰器语法定义的协程函数可以像传统的生成器函数一样运行,但使用 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_YIELD_FROM_ITER
与 GET_AWAITABLE
,当尝试遍历它们 return:
>>> 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
显然 'foo'
不是可等待的,因此尝试用它调用 native()
没有多大意义,但希望很清楚 coroutine
反对它returns 不可迭代,无论其参数如何。
Brett Cannon 对 async
/await
语法的更详细研究:How the heck does async/await work in Python 3.5? 更深入地介绍了这种差异。