2017-02-24 69 views
4

在Python你可以寫一個發電機是可迭代的喜歡:異步生成器不是迭代器?

def generate(count): 
    for x in range(count): 
     yield x 

# as an iterator you can apply the function next() to get the values. 
it = generate(10) 
r0 = next(it) 
r1 = next(it) ... 

當嘗試使用異步迭代器,你得到的「內部收益率異步」的錯誤。 建議的解決方案是實現自己的發電機:

class async_generator: 
    def __aiter__(self): 
     return self 
    async def __anext__(self): 
     await asyncio.sleep() 
     return random.randint(0, 10) 

# But when you try to get the next element 
it = async_generator(10) 
r0 = next(it) 

你得到錯誤「‘async_generator’對象不是一個迭代器」

我認爲,如果你要調用的東西一個Iterator其原因它具有完全相同的接口,這樣我就可以寫異步迭代器和對在很大程度上依賴於未來的框架使用()調用。 如果你需要重寫整個代碼,以便能夠使用異步的任何新的Python的能力是毫無意義的。

我錯過了什麼嗎?

謝謝!

回答

2

所以,@bosnjak說,你可以使用異步爲:

async for ITEM in A_ITER: 
    BLOCK1 
else: # optional 
    BLOCK2 

但是,如果你想手動迭代,你可以簡單的寫:

it = async_iterator() 
await it.__anext__() 

但我不建議這樣做。

我認爲,如果你要調用的東西一個Iterator它,因爲它有完全一樣的接口,這樣我就可以寫異步迭代器和對在很大程度上依賴於下一個()框架使用要求

不,實際上它是不一樣的。常規同步迭代器和異步迭代器之間有區別。而對於有幾個原因:

  1. Python的協同程序是建立在發電機內部頂部
  2. 據蟒蛇的禪,明確優於隱式。這樣你就可以看到代碼可以被暫停的地方。

這就是爲什麼它是不可能使用iternext異步迭代器。你不能將它們用於需要同步迭代器的框架。因此,如果您要使代碼異步,則還必須使用異步框架。其中很少有Here

另外,我想談談迭代器和生成器的幾句話。迭代器是具有__iter____next__方法的特殊對象。而發電機是一個包含yield表達式的特殊功能。 每個生成器都是一個迭代器,但不是反之亦然。異步迭代器和生成器可以接受同樣的事情。是的,因爲python 3.6你可以編寫異步生成器!

async def ticker(delay, to): 
    for i in range(to): 
     yield i 
     await asyncio.sleep(delay) 

您可以閱讀PEP 525更多細節

+1

你說每個生成器都是一個迭代器,並且適用於異步生成器。爲什麼Python抱怨'async_generator'不是一個迭代器呢? – fenceop

+0

但是我怎麼能'''.join([x x中的x異步])'而不是'''.join(x中的x異步xs)'?那只是'[]'對於async_generators有特殊的語法嗎? –

+0

在python 3.6中添加了異步解析的新語法([PEP 530](https://www.python.org/dev/peps/pep-0530/))。所以你可以編寫'[x x async for xs]''。而'(x for x in xs)' - 是生成器表達式(另一個括號可以在作爲函數參數傳遞時簡單省略)。我想你不能用異步代碼創建生成器對象。所以'(x在xs中的x異步)'是無效的語法。 –

3

我相信新的語句中引入了異步發電機:

async for TARGET in ITER: 
    BLOCK 
else: 
    BLOCK2 

根據PEP 492

基本上,這意味着你應該做的:

async for number in generate(10): 
     print(number) 

此外,檢查Differences from generators

原住民協程對象不實行ITER下一個 方法。因此,它們不能被遍歷或傳遞給ITER(), 列表(),元組()等內置插件。它們也不能用於..in循環中的 。企圖用ITER下一個本地 協程對象將導致一個TypeError。

+0

所以,我必須假定有沒有這樣的事情asynchronic迭代器?只是不同步的發電機? – user1275011

+0

這就是我所知道的,但我不是專家,特別是不與異步。 – bosnjak

0

我通過列表中使用這異步循環

class AsyncRange(object): 
    def __init__(self, length): 
     self.length = length 
     self.i = 0 

    async def __aiter__(self): 
     return self 

    async def __anext__(self): 
     index = self.i 
     self.i += 1 
     if self.i <= self.length: 
      return index 
     else: 
      raise StopAsyncIteration 

後來乾脆:

async for i in AsyncRange(my_list): 
    # your code