自从迭代器在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引入了异步迭代器和async for
语法。但我并没有看到对于增加异步迭代器消费者语法的新负担有任何正当理由。
在我的代码中,我有时会处理来自缓存的列表,有时会处理异步生成器:
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())
然而上述方法会有一半的时间失败,出现 TypeError: 'async for' requires an object with __aiter__ method, got list
错误。
主要问题:如何编写代码以应对两种情况?是将列表转换为虚拟异步生成器,还是封装异步生成器以产生列表?
次要问题:是否有任何提案来摆脱(对我来说显然不符合Python风格的)async for
结构?也就是说,为什么常规的 for
循环不能处理异步生成器呢?在可用性方面,Python3.x 是否已经迷失了自己的方向?
for i in await x:
更能传达这个想法,因为它不是循环放弃控制,而是生成器。这也更好地反映了现有异步函数系统的调用者=>await/callee=>async。 - EoghanMfor i in await x:
已经有了明确的含义:x
是某个可等待对象(例如,一个已暂停的异步生成器),可以一次性提供一个完整的(同步)可迭代对象。 - Davis Herring