【问题标题】:Python Memory Error while iterating to a big range迭代到大范围时出现 Python 内存错误
【发布时间】:2016-04-30 15:52:10
【问题描述】:
total = 0
x = 2**32
for i in range(x):
    total = total + i;
print(total) 

我在循环到2**32 的范围时收到MemoryError。有什么方法可以在不耗尽内存的情况下进行迭代?

【问题讨论】:

  • 改用xrange
  • 我猜你的意思是在最后打印sum,否则你最终会打印2**32
  • 简单的答案是切换到 Python 3,它对range 的实现要聪明得多。

标签: python python-2.7


【解决方案1】:

当您尝试创建一个包含前 232 个非负整数的列表时会发生这种情况(我在 Windows 10 系统上使用 Python 2.7.11):

>>> for i in range(2**32): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: range() result has too many items

人们可能会期望,如果问题是内存中同时存在如此大量的项目,则解决方案可能是通过生成器一次处理一个项目......但事实并非如此:

>>> for i in xrange(2**32): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: Python int too large to convert to C long

xrange()内置函数的文档解释了为什么会出现这个错误:

CPython 实现细节:xrange() 旨在简单快速。实现可能会施加限制来实现这一点。 Python 的 C 实现将所有参数限制为原生 C long(“短”Python 整数),并且还要求元素的数量适合原生 C long。

问题是 232 不能作为输入参数传递给 xrange,因为该数字大于 Python 中的最大“短”整数。试试这个来说服自己:

>>> import sys
>>> sys.maxint       # 2**31 - 1
2147483647
>>> sys.maxint + 1   # 2**31 is automatically converted to "long" int
2147483648L
>>> 2**31
2147483648L

如果您需要重复执行计算超过 231 次(以下示例中为 234 次),您可以使用嵌套的 for 循环:

>>> loops = 0
>>> for i in xrange(2**4):
...    for j in xrange(2**30):
...        # do stuff
...        loops += 1
...
>>> loops
17179869184L
>>> 2**34
17179869184L

上面的代码是一个相当幼稚的解决方法。 while 循环似乎是一个更合适的解决方案:

>>> loops = 0
>>> while loops < 2**34:
...    # do stuff
...    loops += 1
...
>>> loops
17179869184L

【讨论】:

  • Python 3 中的 range 函数与 Python 2 的 xrange 类似,但适用于任意大小的整数。
【解决方案2】:
  1. range 在内存中创建一个列表。使用xrange 获取一个生成器对象,它一次给你一个数字。

  2. 有更好的方法可以对从1n 的一系列数字求和,例如(n(n+1))/2

【讨论】:

  • 是的 (n(n+1))/2 更好,但我正在测试是否可以循环到 y 的程度,谢谢
【解决方案3】:

对于蛮力方法,试试这个:

x = sum(i for i in xrange(2**32))

上面会更高效,因为它使用xrange 懒惰地生成数字,并且它还使用带有sum() 的生成器表达式来避免生成立即被丢弃的临时数据。

但这仍然需要一些时间,因为2**32 是一个很大的数字。解决这个问题的聪明方法是使用公式,正如@DeepSpace 所建议的那样:

n = 2**32 - 1
x = (n * (n + 1)) / 2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多