python - python:迭代列表或异步生成器
问题描述
由于迭代器是在 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
.
主要问题:如何写这个以便我们可以处理任何一个?我应该尝试将列表转换为虚拟异步生成器,还是包装异步生成器以生成列表?
Side Quest:是否有任何建议可以摆脱(对我来说显然是非pythonic)async for
构造,即为什么常规for
循环不能处理异步生成器?Python3x 在可用性方面失去了它的方式吗?
解决方案
语法的存在是为了警告您,您的“循环”实际上可能包括暂停整个调用,允许其他代码运行,以便您知道在每次迭代的顶部有适当的数据处于一致的状态。它不会去任何地方。
当然,协程不必暂停,您可以使用它来包装任何可迭代的微不足道的东西:
async def desync(it):
for x in it: yield x
这比相反的数字更有用——它仍然是异步的,因为它必须——聚集到一个列表中:
async def gather(ai):
ret=[]
async for x in ai: ret.append(x)
return ret
因为它允许在完全异步的情况下进行适当的交错。
推荐阅读
- terraform - Terraform 外部数据源作为提供者的输入
- markdown - Hugo:如何将图像存储在与帖子相同的目录中?
- php - 警告:mysqli_stmt_bind_param():类型定义字符串中的元素数与中的绑定变量数不匹配
- javascript - 在量角器循环内执行多个 it 块并使用 IT 块中的变量
- reactjs - 获取状态中的递增变量
- ruby-on-rails - Rails 5 InvalidAuthenticityToken Coffeescript
- php - 将变量传递给 Blade 导致 increment() 将 DB 字段增加两次
- python - 如何从给定的二叉搜索树的后序遍历中找到前序遍历
- pandas - 向数据框添加列
- eclipse - 为什么 Eclipse 以红色突出显示我的代码以及如何将其关闭?