RAM 过载 - itertools
RAM overload - itertools
这是我正在尝试做的一个简单示例以及我遇到的错误:
for symbol in itertools.product(list_a, repeat=8):
list_b.append(symbol)
之后我也会从该列表中排除组合,如下所示:
for combination in list_b:
valid_b = True
for symbols in range(len(list_exclude)):
if list_exclude[symbols] in combination:
valid_b = False
else:
pass
if valid_b:
new_list.append(combination)
我听说以某种方式将流程分块可能会有所帮助,但不确定如何在此处完成。
我也在为此使用多处理。
当我 运行 它时,我得到“MemoryError”
你会怎么做?
我所做的这个小改动可以为您节省一些 ram 使用量。
for combination in list_b:
valid_b = True
for symbols in list_exclude:
if symbols in combination:
valid_b = False
else:
pass
if valid_b:
new_list.append(combination)
不要预先计算任何东西,尤其是第一个完整列表:
def symbols(lst, exclude):
for symbol in map(''.join, itertools.product(lst, repeat=8)):
if any(map(symbol.__contains__, exclude)):
continue
yield symbol
现在使用生成器,因为您需要延迟计算元素。请记住,由于它是对数据进行预过滤,因此即使 list(symbols(list_a, list_exclude))
也会比您最初写的便宜得多。
这里是发生了什么的细目:
itertools.product
是一个生成器。这意味着它在不保留对任何先前项目的引用的情况下生成输出。它 returns 的每个元素都是 tuple
包含输入元素的某种组合。
既然要比较字符串,就需要对tuple
进行转换。因此,''.join
。将其映射到 itertools.product
生成的每个 tuple
将这些元素转换为字符串。例如:
>>> ''.join(('$', '$', '&', '&', '♀', '@', '%', '$'))
'$$&&♀@%$'
过滤每个如此创建的 symbol
可以通过检查是否包含 excludes
中的任何项目来完成。你可以用
之类的东西来做到这一点
[ex in symbol for ex in exclude]
操作... in symbol
是通过魔术方法symbol.__contains__
实现的。因此,您可以 map
该方法用于 exclude
.
的每个元素
由于symbol
中包含的exclude
的第一个元素使它无效,所以不需要检查余数。这称为短路,并在 any
函数中实现。请注意,因为 map
是一个生成器,所以一旦找到匹配项,实际上将不会计算剩余的元素。这与使用列表理解不同,后者预先计算所有元素。
将 yield
放入您的函数中会将其变成生成器函数。这意味着当您调用 symbols(...)
时,它 returns 是一个您可以迭代的生成器对象。在您对其调用 next
之前,该对象不会预先计算任何内容。因此,如果您将数据写入文件(例如),那么只有当前结果会立即进入内存。写出大量结果可能需要很长时间,但您的内存使用量不应因此而飙升。
这是我正在尝试做的一个简单示例以及我遇到的错误:
for symbol in itertools.product(list_a, repeat=8):
list_b.append(symbol)
之后我也会从该列表中排除组合,如下所示:
for combination in list_b:
valid_b = True
for symbols in range(len(list_exclude)):
if list_exclude[symbols] in combination:
valid_b = False
else:
pass
if valid_b:
new_list.append(combination)
我听说以某种方式将流程分块可能会有所帮助,但不确定如何在此处完成。
我也在为此使用多处理。
当我 运行 它时,我得到“MemoryError”
你会怎么做?
我所做的这个小改动可以为您节省一些 ram 使用量。
for combination in list_b:
valid_b = True
for symbols in list_exclude:
if symbols in combination:
valid_b = False
else:
pass
if valid_b:
new_list.append(combination)
不要预先计算任何东西,尤其是第一个完整列表:
def symbols(lst, exclude):
for symbol in map(''.join, itertools.product(lst, repeat=8)):
if any(map(symbol.__contains__, exclude)):
continue
yield symbol
现在使用生成器,因为您需要延迟计算元素。请记住,由于它是对数据进行预过滤,因此即使 list(symbols(list_a, list_exclude))
也会比您最初写的便宜得多。
这里是发生了什么的细目:
itertools.product
是一个生成器。这意味着它在不保留对任何先前项目的引用的情况下生成输出。它 returns 的每个元素都是tuple
包含输入元素的某种组合。既然要比较字符串,就需要对
tuple
进行转换。因此,''.join
。将其映射到itertools.product
生成的每个tuple
将这些元素转换为字符串。例如:>>> ''.join(('$', '$', '&', '&', '♀', '@', '%', '$')) '$$&&♀@%$'
过滤每个如此创建的
之类的东西来做到这一点symbol
可以通过检查是否包含excludes
中的任何项目来完成。你可以用[ex in symbol for ex in exclude]
操作
的每个元素... in symbol
是通过魔术方法symbol.__contains__
实现的。因此,您可以map
该方法用于exclude
.由于
symbol
中包含的exclude
的第一个元素使它无效,所以不需要检查余数。这称为短路,并在any
函数中实现。请注意,因为map
是一个生成器,所以一旦找到匹配项,实际上将不会计算剩余的元素。这与使用列表理解不同,后者预先计算所有元素。将
yield
放入您的函数中会将其变成生成器函数。这意味着当您调用symbols(...)
时,它 returns 是一个您可以迭代的生成器对象。在您对其调用next
之前,该对象不会预先计算任何内容。因此,如果您将数据写入文件(例如),那么只有当前结果会立即进入内存。写出大量结果可能需要很长时间,但您的内存使用量不应因此而飙升。