通过返回迭代器而不是列表来保护Py3k内存

时间:2009-03-31 13:55:18

标签: python memory list iterator python-3.x

用于在Python 2.x中返回列表的许多方法现在似乎都在Py3k中返回迭代器

迭代器也是生成器表达式吗?懒惰的评价?

因此,有了这个,python的内存占用将大幅减少。不是吗?

使用内置脚本从2to3转换的程序怎么样?

为了兼容性,内置工具是否将所有返回的迭代器显式转换为列表?如果是这样,那么Py3k的较低内存占用优势在转换后的程序中并不明显。是吗?

3 个答案:

答案 0 :(得分:7)

其中许多不完全是迭代器,而是特殊的视图对象。例如,range()现在返回类似于旧xrange对象的东西 - 它仍然可以被索引,但是懒惰地根据需要构造整数。

类似地,dict.keys()给出了一个dict_keys对象,它在dict上实现了一个视图,而不是创建一个带有密钥副本的新列表。

这对内存占用的影响可能取决于程序。当然,除非你真的需要列表,否则更多的重点是使用迭代器,而使用列表通常是python2中的默认情况。这将导致平均程序可能更高效。实际上有大量节省的情况可能已经作为python2程序中的迭代器实现了,但是,因为真正大的内存使用率将会脱颖而出,并且更有可能已经解决。 (例如,文件迭代器已经比旧的file.readlines()方法具有更高的内存效率)

转换是由2to3工具完成的,通常会将range()之类的东西转换为迭代器,它可以安全地确定不需要真正的列表,所以代码如下:

for x in range(10): print x

将切换到新的range()对象,不再创建列表,因此将获得减少的内存优势,但代码如下:

x = range(20)

将转换为:

x = list(range(20))

因为转换器无法知道代码是否需要x中的真实列表对象。

答案 1 :(得分:1)

  

迭代器也是生成器表达式吗?懒惰的评价?

迭代器只是一个带有下一个方法的对象。当函数返回迭代器时,大多数时候文档的含义是它的结果是延迟加载的。

  

因此,有了这个,python的内存占用将大幅减少。不是吗?

这取决于。我猜想普通程序不会注意到巨大的差异。如果您有一个大型数据集,迭代器优于列表的性能优势实际上非常重要。您可能希望看到this question

答案 2 :(得分:0)

迭代器优于列表的最大好处之一不是内存,实际上是计算时间。例如,在Python 2中:

for i in range(1000000):  # spend a bunch of time making a big list
    if i == 0:
        break  # Building the list was a waste since we only looped once

现在举个例子:

for i in xrange(1000000):  # starts loop almost immediately
    if i == 0:
        break  # we did't waste time even if we break early

虽然这个例子是设计的,但用例并不是:循环经常被打破。构建一个仅使用部分列表的整个列表是一种浪费,除非您不止一次地使用它。如果是这种情况,您可以显式构建一个列表:r = list(range(100))。这就是为什么迭代器是Python 3中更多地方的默认值;你没有任何东西,因为你仍然可以在需要时明确地创建列表(或其他容器)。但是当你打算做的只是迭代一次迭代时,你并没有被迫(我认为这是更常见的情况)。