Python で次のようなエラーが出たときの解消方法についてです。
TypeError: object async_generator can't be used in 'await' expression
確認時の Python バージョン
- Python
3.12.0
エラー
次のコードで再現できます。
sample_async_generator.py
:
import asyncio
async def main():
numbers = await async_range(5)
# or
# numbers = [x for x in await async_range(5)]
print(numbers)
async def async_range(n):
for i in range(n):
yield i
await asyncio.sleep(0.01)
if __name__ == "__main__":
asyncio.run(main())
❯ python sample_async_generator.py
Traceback (most recent call last):
File "/path/to/file/sample_async_generator.py", line 16, in <module>
asyncio.run(main())
File "/path/to/runtime/python/3.12.0/lib/python3.12/asyncio/runners.py", line 194, in run
return runner.run(main)
^^^^^^^^^^^^^^^^
File "/path/to/runtime/python/3.12.0/lib/python3.12/asyncio/runners.py", line 118, in run
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/path/to/runtime/python/3.12.0/lib/python3.12/asyncio/base_events.py", line 664, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/<path>/sample_async_generator.py", line 5, in main
numbers = await async_range(5)
^^^^^^^^^^^^^^^^^^^^
TypeError: object async_generator can't be used in 'await' expression
原因
まさにエラーメッセージのとおりですが、 async_generator
オブジェクトには await
が使えないことが原因です。
上のサンプルだと、 async def
で定義されている async_range()
の戻り値は coroutine
オブジェクトではなく async_generator
オブジェクトですが、それに対して await
してしまっていることが問題です。
解決方法
async_generator
オブジェクトには await
ではなく async for
を使います。
上のサンプルは次のように書き換えると正しく動きます。
sample_async_generator_fixed.py
:
import asyncio
async def main():
# `async for` を使う
numbers = [x async for x in async_range(5)]
print(numbers)
# or
async for number in async_range(5):
print(number)
# ↑ は ↓ のコードとほぼ等価
iterator = async_range(5)
running = True
while running:
try:
number = await iterator.__anext__()
except StopAsyncIteration:
running = False
else:
print(number)
async def async_range(n):
for i in range(n):
yield i
await asyncio.sleep(0.01)
if __name__ == "__main__":
asyncio.run(main())