2016-06-25 24 views
10

Per PEP-492 Próbuję zaimplementować asynchroniczny iterator, taki że mogę zrobić np.Implementacja asynchronicznego iteratora

async for foo in bar: 
    ... 

Tutaj jest trywialny przykład, podobny do tego w docs, z bardzo podstawowego testu instancji i asynchronicznym iteracji:

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 

Jednak, kiedy wykonać mój testowy pakiet, widzę :

=================================== 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 ====================== 

Dlaczego mój TestImplementation wydaje się być nieważny? O ile mogę powiedzieć, że spotyka się z protokołem:

  1. Obiekt musi implementować metodę __aiter__ ... powrocie asynchroniczny obiekt iteratora.
  2. Obiekt asynchronicznego iteratora musi implementować metodę __anext__ ... zwracając wartość oczekiwaną.
  3. Aby zatrzymać iterację, __anext__ musi podnieść wyjątek StopAsyncIteration.

ta zawodzi z najnowszych wydanych wersji Pythona (3.5.1), py.test (2.9.2) i pytest-asyncio (0.4.1).

+13

Po blisko 3 latach w końcu [zadać pytanie] (http://stackoverflow.com/users/3001761/jonrsharpe?tab=questions). Kudos –

+6

@BhargavRao Miałem ochotę 2,076: 1 było o prawo; o) – jonrsharpe

+0

Działa dla mnie z pytest 2.9.2. Jakiej wersji używasz? –

Odpowiedz

21

Jeśli czytasz a little further down the documentation wspomina, że ​​(Kopalnia nacisk):

PEP 492 została przyjęta w CPython 3.5.0 z __aiter__ zdefiniowanej jako metoda , że spodziewano się powrotu awaitable postanawiając asynchroniczny iterator.

W wersji 3.5.2 (jako że PEP 492 został tymczasowo zaakceptowany) zaktualizowano protokół __aiter__, aby bezpośrednio zwracać asynchroniczne iteratory.

Dlatego dla wersji wcześniejszych niż 3.5.2 (wydana 2016/6/27) dokumentacja jest nieco poza krokiem, aby napisać działający asynchroniczny iterator. Poprawiona wersja dla 3.5.0 i 3.5.1 wygląda następująco:

class TestImplementation: 
    async def __aiter__(self): 
    #^note 
     return self 
    async def __anext__(self): 
     raise StopAsyncIteration 

ten został wprowadzony na zamknięciu bug #27243 i jest trochę jaśniej w data model documentation, co sugeruje również sposób pisania kodu wstecznie kompatybilne.

+10

Po 3 latach musiałeś odpowiedzieć na własne pytanie :) –

+2

@PadraicCunningham niektóre nawyki są trudne do zerwania ... – jonrsharpe

+5

@Padraic [Następnym razem, gdy jon zadaje pytanie, trzymaj się z dala od niego] (https: // www. youtube.com/watch?v=4F4qzPbcFiA);) –