python - 如何将异步迭代器视为同步迭代器?
问题描述
理解符号支持从异步迭代器生成列表。如何在自定义列表类中执行此操作?
当然,你可以使用list.append
来生成列表,但我想知道聪明的方式。
import asyncio
class MyList(list):
pass
async def iterate():
yield 1
yield 2
async def main():
return [x async for x in iterate()]
# return MyList(x async for x in iterate()) # NG
# return MyList([x async for x in iterate()]) # OK However, there is a lot of waste because the list is generated twice
result = asyncio.run(main())
print(result) # [1, 2]
解决方案
Python 魔术方法不是异步的 - 例如,在您main()
的await
构造MyList
函数中,它也不能是异步的。正常的方法是提供一种方法,例如extend_async
并使用它:
class MyList(list):
async def extend_async(self, aiter):
async for obj in aiter:
self.append(obj)
async def main():
lst = MyList()
await lst.extend_async(x async for x in iterate())
return lst
或者,如果你想main
缩短,你可以创建一个助手:
class MyList(list):
@staticmethod
async def from_aiter(aiter):
self = MyList()
async for obj in aiter:
self.append(obj)
return self
async def main():
return await MyList.from_aiter(x async for x in iterate())
最后,说了这么多……如果你真的坚持异步构造,你可以使用元类来破解它:
class Hack(type):
async def __call__(cls, aiter):
self = type.__call__(cls)
await self.extend_async(aiter)
return self
class MyList(list, metaclass=Hack):
async def extend_async(self, aiter):
async for obj in aiter:
self.append(obj)
async def main():
return await MyList(x async for x in iterate())
但是后面的代码仅作为学习练习,不要尝试在生产中使用它。
推荐阅读
- google-data-studio - LEGACY 架构和 Data Studio Apps 脚本服务之间的差异
- java - 具有n级依赖关系的多模块maven spring boot项目
- c++ - QInputDialog 为 getDouble() 显示逗号而不是点
- python - 需要返回选项卡空间意图。不需要 4 个空格和警告
- html - CSS表格单元格和引导程序的奇怪对齐问题
- javascript - 多个数组的长度
- php - 什么是 Sylius 资源中的“驱动程序”
- asp.net-web-api - 如何为 Asp.Net Identity 自定义表名(例如从 AspNetUsers 更改为自定义名称)
- python - 使用来自另一个数据框的匹配值列表创建数据框列
- c++ - 对 Eigen QR 分解感到困惑