首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >*解压缩是否使用生成器表达式上的内存?

*解压缩是否使用生成器表达式上的内存?
EN

Stack Overflow用户
提问于 2022-03-07 18:55:50
回答 1查看 170关注 0票数 0

上下文示例:

调用*解压缩输入是否将所有内容都放入内存?我希望不是,只是想确认一下我的理解。

代码语言:javascript
复制
input = (x for x in ((1, 'abc'), (2, 'def'))) # generator expression
unzipped = zip(*input) # Does *input get completely unpacked or stay memory efficient?
first_items = next(unzipped)
print(first_items)
# >> (1, 2)
EN

回答 1

Stack Overflow用户

发布于 2022-03-08 20:11:45

解压缩急切地解压缩了可迭代性的顶层,因此在您的示例中,是的,在实际调用zip之前,它将运行生成器表达式直到完成,然后执行等效的zip((1, 'abc'), (2, 'def'))。但是,如果生成器中的迭代器本身是懒惰的迭代器,那么zip根本不会预先读取它们,这通常是更重要的节省。例如,如果input定义为:

代码语言:javascript
复制
input = (open(name) for name in ('file1', 'file2'))

然后,同时:

代码语言:javascript
复制
unzipped = zip(*input)

是否热切地open了这两个文件(所以您可能已经使用了listcomp;genexpr并没有真正保存任何内容),它不会从其中任何一个文件中读取一行。当你这样做时:

代码语言:javascript
复制
first_items = next(unzipped)

它将从每一行中读取一行,但它不会读取文件的其余部分,直到您请求更多的项(从技术上讲,在遮罩下,文件对象是块读取的,所以它将读取的不仅仅是它返回的行,但这是实现细节;它不会仅仅为了给您第一行而忽略整个10 GB的文件)。

这是*解压缩的本质;接收函数需要在调用它时填充它的参数。如果你定义:

代码语言:javascript
复制
def foo(a, b):
    print(b)
    print(a)

如果调用方能够执行foo(*iterator),则迭代器在为a生成值时会引发异常,但只有在执行print(b)时才会看到它(此时,迭代器必须提前两次才能懒散地填充b)。没有人会知道到底出了什么问题。实际上,每个函数都必须处理这样一个事实,即简单地加载其参数(不对其做任何操作)可能会引发异常。不漂亮。

如果处理延迟迭代器是合理的(这不是针对zip的;第一个输出无论如何都需要从所有参数中读取,所以最好是将参数的实现从构建的那一刻推迟到第一次从它提取值时,除非您构建了一个zip对象并没有使用它),只需直接接受迭代器。或者两者兼而有之;itertoolschain允许两种方法同时进行:

代码语言:javascript
复制
for item in chain(iter1, iter2):

懒惰的人:

代码语言:javascript
复制
for item in chain.from_iterable(iter_of_iters):

调用技术,正是因为它不想强迫使用iter_of_iters的人在将第一个值链接到一个值之前实现内存中的所有迭代器(这就是for item in chain(*iter_of_iters):所需要的)。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71385948

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档