web-dev-qa-db-ja.com

python asyncioで「戻ります...」を返す理由はありますか?

私はjsでそれがawaitステートメントの前にreturnを行うために何も追加しないことを知っています(すなわち、return await ...)ですが、pythonの場合もそうですか。それとも、どういうわけか、具体化の可能性が高くなったり、異なったりしますか?

2つが同等でない場合、ベストプラクティスは何ですか?

3
Uri

与えられた:

async def foo() -> str:
    return 'bar'

fooを呼び出したときに得られるのは Awaitable で、これは明らかにawaitしたい。考える必要があるのは、関数の戻り値です。たとえば、これを行うことができます:

def bar() -> Awaitable[str]:
    return foo()  # foo as defined above

ここでbarは同期関数ですが、Awaitableを返すstrを返します。

async def bar() -> str:
    return await foo()

ここでbar自体はasyncであり、呼び出されるとAwaitableになり、上記と同様にstrになります。これらの2つの使用法には実際の違いはありません。違いはここに表示されます:

async def bar() -> Awaitable[str]:
    return foo()

ここでbarを呼び出すとAwaitableが生成され、その結果Awaitableが生成され、strが生成されます。かなり違う。上記を単純に使用すると、次のような結果が得られます。

>>> asyncio.run(bar())
<coroutine object foo at 0x108706290>
RuntimeWarning: coroutine 'foo' was never awaited

経験則として、asyncへのすべての呼び出しは、どこかでawaitedする必要があります。 2つのasyncasync def fooおよびasync def bar)がawaitbarがない場合、barの呼び出し元はawaitを2回実行する必要がありますが、これは奇妙です。

5
deceze

TL)@deceze回答のDR。

はい、理由があります。コルーチンを呼び出す場合は、常にreturn await

Async関数は、単純なreturnであっても、常にAwaitableを返します。実際の結果を取得するには、awaitを呼び出します。 return awaitがない場合、結果は余分にラップされたAwaitableであり、2回待機する必要があります。ドキュメントを参照してください。

import asyncio

async def nested():
    return 42

async def main():
    # Nothing happens if we just call "nested()".
    # A coroutine object is created but not awaited,
    # so it *won't run at all*.
    nested()

    # Let's do it differently now and await it:
    print(await nested())  # will print "42".

asyncio.run(main())

0
dre-hh