Is the asynchronous generator an iterator?

In Python, you can write a generator that can be done as follows:

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) ... 

When you try to use an asynchronous iterator, you get a "yield in async" error. The proposed solution is to implement your own generator:

 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) 

You get the error "async_generator object" is not an iterator "

I think if you are going to call something Iterator because it has exactly the same interface, so I can just write asynchronous iterators and use them in a structure that is heavily dependent on the following () calls. Any new Python features are pointless if you need to rewrite all the code in order to be able to use async.

Did I miss something?

Thanks!

+5
source share
3 answers

So, as @bosnjak said, you can use async for:

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

But if you want to iterate manually, you can simply write:

 it = async_iterator() await it.__anext__() 

But I would not recommend doing this.

I think that if you are going to call something Iterator your own, because it has exactly the same interface, so I can just write asynchronous iterators and use them in a structure that depends heavily on the following () calls

No, this is not the same. There is a difference between regular synchronous iterators and asynchronous. And there are several reasons for this:

  • Python consoles are built on top of built-in generators.
  • According to Zen python, explicit is better than implicit. So you really see where the code can be paused.

This is why it is not possible to use iter and next with asynchronous iterators. And you cannot use them with frameworks waiting for synchronous iterators. Therefore, if you intend to make your code asynchronous, you also need to use asynchronous frameworks. There are few of them.

In addition, I would like to say a few words about iterators and generators. An iterator is a special object that has the __iter__ and __next__ . While the generator is a special function containing the expression yield . Each generator is an iterator, but not vice versa . The same is acceptable for asynchronous iterators and generators. Yes, with python 3.6 you can write asynchronous generators!

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

Learn more about PEP 525

+2
source

I believe a new expression has been introduced for async generators:

 async for TARGET in ITER: BLOCK else: BLOCK2 

according to PEP 492 .

This would basically mean that you should:

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

Also, check Differences from Generators :

Native coroutine objects do not implement the iter and next methods. Therefore, they cannot be repeated or passed to iter (), list (), tuple () and other built-in modules. They also cannot be used in for..in loop. Attempting to use iter or next on the native coroutine object will result in a TypeError.

+3
source

I used this for async loop through list

 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 

then just:

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

Source: https://habr.com/ru/post/1264703/


All Articles