私が見たasyncio
ライブラリで、
@asyncio.coroutine
def function():
...
そして
async def function():
...
交換可能に使用されます。
2つの間に機能的な違いはありますか?
はい、_async def
_構文を使用するネイティブコルーチンと_asyncio.coroutine
_デコレータを使用するジェネレータベースのコルーチンには機能的な違いがあります。
PEP 492 によると、_async def
_構文が導入されます。
ネイティブコルーチンオブジェクトは_
__iter__
_および___next__
_メソッドを実装しません。そのため、iter()
、list()
、Tuple()
およびその他の組み込み関数を繰り返し処理したり、それらに渡すことはできません。また、_for..in
_ループでは使用できません。ネイティブコルーチンオブジェクトで_
__iter__
_または___next__
_を使用しようとすると、TypeErrorが発生します。プレーンジェネレーターは_
yield from
_を使用できませんネイティブコルーチン:そうするとTypeErrorが発生します。ジェネレーターベースのコルーチン(asyncioコードは_
@asyncio.coroutine
_で装飾する必要があります)_yield from
_ネイティブコルーチンオブジェクト.
inspect.isgenerator()
およびinspect.isgeneratorfunction()
は、native coroutineオブジェクトおよびnative coroutine functionsに対してFalse
を返します。
上記のポイント1は、_@asyncio.coroutine
_デコレーター構文を使用して定義されたコルーチン関数は従来のジェネレーター関数として動作できますが、_async def
_構文で定義された関数は動作できないことを意味します。
2つの構文で定義された、表面上は同等の2つの最小限のコルーチン関数を以下に示します。
_import asyncio
@asyncio.coroutine
def decorated(x):
yield from x
async def native(x):
await x
_
これら2つの関数のバイトコードはほぼ同じですが、
_>>> 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
_であり、返されるオブジェクトを反復しようとすると、まったく異なる動作をします。
_>>> 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
オブジェクトが引数に関係なく、反復可能。
Brett Cannonによるasync
/await
構文のより詳細な調査: Python 3.5? で非同期/待機がどのように機能するかこの違いをより深くカバーしています。
async def
はPython 3.5。からの新しい構文です。await
、async with
およびasync for
内部async def
s。
@coroutine
はasync def
しかし、Python 3.4+で動作し、yield from
の代わりにawait
を作成します。
実用的な観点からは、@coroutine
Pythonが3.5+の場合。
Python 3.5coroutines
が正式に特殊タイプになったため、async def
構文とawait
ステートメント。
それ以前は、Python 3.4は、通常の関数をgenerators
にラップすることでコルーチンを作成しました。したがって、デコレーター構文、およびよりジェネレーターに似たyield from
。