简体   繁体   English

python:迭代列表或异步生成器

[英]python: iterate over either a list or an async generator

Since iterators were introduced in python, it's always been possible to not care whether you are dealing with an iterator or a list:由于迭代器是在 python 中引入的,因此总是可以不关心您是在处理迭代器还是列表:

from random import random

def gen_list():
    print('gen')
    for i in range(10):
        yield i

def return_list():
    print('return')
    return [i for i in range(10)]


if random() > 0.5:
    x = gen_list()
else:
    x = return_list()

for i in x:
    pass

PEP 492 introduced asynchronous iterators and the async for syntax. PEP 492 引入了异步迭代器async for语法。 What I can't see is any justification for the new burden of adding syntax to the consumer of the async iterator.我看不到为异步迭代器的使用者添加语法的新负担的任何理由。

In my code, I sometimes am dealing with a list (from a cache), and sometimes with an async generator:在我的代码中,我有时处理一个列表(来自缓存),有时处理一个异步生成器:

import asyncio
from random import random

def is_small_and_in_cache():
    if random() > 0.5:
        print('in fake cache')
        return [i for i in range(10)]

async def get_progressively():
    print('gen')
    for i in range(10):
        # e.g. an await here
        await asyncio.sleep(0.1)
        yield i

async def main():
    x = is_small_and_in_cache()
    if x is None:
        x = get_progressively()

    async for i in x:
        pass

asyncio.run(main())

But the above fails (half the time) with TypeError: 'async for' requires an object with __aiter__ method, got list .但上述失败(一半时间) TypeError: 'async for' requires an object with __aiter__ method, got list

Main Question: How to write this so that we can deal with either?主要问题:如何写这个以便我们可以处理任何一个? Should I try to convert the list to a dummy async generator, or wrap the async generator so that it produces a list?我应该尝试将列表转换为虚拟异步生成器,还是包装异步生成器以生成列表?

Side Quest: Are there any proposals to get rid of the (clearly unpythonic, to me) async for construct, ie why can't a regular for loop handle an asynchronous generator? Side Quest:是否有任何建议可以摆脱(对我来说显然是非pythonic) async for构造,即为什么常规for循环不能处理异步生成器? Has Python3x lost it's way in terms of usability?? Python3x 在可用性方面失去了它的方式吗?

The syntax exists to warn you that your “loop” might actually include suspending your entire call, allowing other code to run, so that you know to have appropriate data in a consistent state at the top of each iteration.语法的存在是为了警告您,您的“循环”实际上可能包括暂停整个调用,允许其他代码运行,以便您知道在每次迭代顶部的一致 state 中具有适当的数据。 It's not going anywhere.它不会去任何地方。

Of course, a coroutine doesn't have to suspend, and you can use that to make wrapping any iterable trivial:当然,协程不必暂停,您可以使用它来包装任何可迭代的微不足道的东西:

async def desync(it):
  for x in it: yield x

This is more generally useful than the opposite number which—still asynchronously, as it must—gathers into a list:这比相反的数字更有用——它仍然是异步的,因为它必须——聚集到一个列表中:

async def gather(ai):
  ret=[]
  async for x in ai: ret.append(x)
  return ret

since it allows for proper interleaving in the fully asynchronous case.因为它允许在完全异步的情况下进行适当的交错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM