Per PEP-492 非同期イテレータを実装しようとしています。
async for foo in bar:
...
これは、ドキュメントの例と同様の簡単な例であり、インスタンス化と非同期反復の非常に基本的なテストが含まれています。
import pytest
class TestImplementation:
def __aiter__(self):
return self
async def __anext__(self):
raise StopAsyncIteration
@pytest.mark.asyncio # note use of pytest-asyncio marker
async def test_async_for():
async for _ in TestImplementation():
pass
ただし、テストスイートを実行すると、次のように表示されます。
=================================== FAILURES ===================================
________________________________ test_async_for ________________________________
@pytest.mark.asyncio
async def test_async_for():
> async for _ in TestImplementation():
E TypeError: 'async for' received an invalid object from __aiter__: TestImplementation
...: TypeError
===================== 1 failed, ... passed in 2.89 seconds ======================
TestImplementation
が無効に見えるのはなぜですか?私が知る限り、それはプロトコルを満たしています:
- オブジェクトは
__aiter__
メソッドを実装する必要があります...非同期イテレータオブジェクトを返します。- 非同期イテレータオブジェクトは、
__anext__
メソッドを実装する必要があります... awaitableを返します。- 反復を停止するには、
__anext__
はStopAsyncIteration
例外を発生させる必要があります。
これは、最新リリースバージョンのPython(3.5.1)、py.test
(2.9.2)、およびpytest-asyncio
(0.4.1)では失敗します。
あなたが読んだ場合 ドキュメントの少し下に それはそれを述べています(私の強調):
PEP 492は、CPython3.5.0で
__aiter__
メソッドとして定義され、返されることが期待されていました非同期イテレータへの待機可能な解決。3.5.2では(PEP 492が暫定的に受け入れられたため)、
__aiter__
プロトコルが更新され、非同期イテレータが直接返されるようになりました。
したがって、3.5.2(2016/6/27でリリース)より前のバージョンの場合、ドキュメントは、動作する非同期イテレーターの記述方法と少しずれています。 3.5.0および3.5.1の修正バージョンは次のようになります。
class TestImplementation:
async def __aiter__(self):
# ^ note
return self
async def __anext__(self):
raise StopAsyncIteration
これは、終了時に導入されました bug#2724 そして データモデルのドキュメント で少し明確になり、下位互換性のあるコードを書く方法も示唆しています。
非同期イテレータはPython 3.6 PEP-525 を参照)に実装されています
その場合、async for
を使用するためにTestImplementationはまったく必要ありません。 yield
(PEP-525からの例)を使用できます。
async def ticker(delay, to):
"""Yield numbers from 0 to `to` every `delay` seconds."""
for i in range(to):
yield i
await asyncio.sleep(delay)
その後、期待どおりにasync for
を使用できます。
async for i in ticker(1, 10):
print(f'Tick #{i}')